Dispatch first bloc event or cubit method, on page start inside StatelessWidget - flutter

I have 10 buttons in main menu of my app and each of them contains BlocBuilder inside them.
So when I click on those buttons to open a new page, I want to dispatch the first event, but I don't know how. I can change all classes to stateful widget and then call bloc.dispatch(event) inside initialState() function, but I would like to discover another way, and not sure whether it's the best way

In order to trigger the first event/method call inside BlocBuilder I had to add bloc argument and give parameter provided my BlocProvider, only after this I managed to call my method.
BlocBuilder<MyCubit, MyState>(
bloc: BlocProvider.of<MyCubit>(context)..myFunction(),
builder: (BuildContext context, state) {
//Your code...
}

you can use .. operator to add event while declaring like
BlocProvider(
create: (context) => FirstBloc()..add(InitialiEvent()), // <-- first event,
child: BlocBuilder<FirstBloc, FirstState>(
builder: (BuildContext context, state) {
...
},
),
or you can do it inside the initState method as well

Related

Why it's useless trying to pass 'context' to showDialog?

I'm using the plugin 'Provider' to get some information and when I'm trying to show a dialog and get a info from my Provider, something weird happened.
The code seems like this:
showDialog(
context: context,
builder: (context) {
return LoadingDialog(); //LoadingDialog is one of my own class ,which extends AlertDialog.
}
);
but it throws a error like:
ProviderNotFoundException (Error: Could not find the correct Provider<LoginState> above this LoadingDialog Widget
So I set a breakpoint and checked the context in the class LoadingDialog, but it's like:
StatelessElement(LoadingDialog(dirty))
So i think the context from the outside page failed to pass into this dialog. So later I read the Flutter API doc and it says:
This function takes a builder which typically builds a Dialog widget. Content below the dialog is dimmed with a ModalBarrier. The widget returned by the builder does not share a context with the location that showDialog is originally called from. Use a StatefulBuilder or a custom StatefulWidget if the dialog needs to update dynamically.
So i tried to use the StatefulBuilder,the code seems like this:
showDialog(
context: context,
builder: (context) {
bool tempLoginState = Provider.of<LoginState>(context, listen: true).getState;//my own method returns true.
return AlertDialog(
content: StatefulBuilder(
builder: (context, setState){
//my dialog detail codes
}
)
)
}
);
But actually, the first line in the builder:
bool tempLoginState = Provider.of<LoginState>(context, listen: true).getState;
it doesn't work, because the context here is also the same as
StatelessElement(LoadingDialog(dirty))
So how can I pass the context to the dialog on earth? Thank you for your ansering.

How can we use the same instance of widget (with no rebuild) in a Navigator in flutter?

How can we reuse same widget with the same state, just building it once, and rebuilding only on changes at app state model (obviously currently it is being rebuilt each time when I trigger the Navigator)?
Navigator.of(context).push( MaterialPageRoute(
builder: (context) => SchedulerView(), ), );
SchedulerView is the target widget.
Thank you.
I'm guessing that your issue is not the rebuild (which is a call of the build() function triggered by the framework) but the creation of another SchedulerView instance because the Navigator calls the constructor SchedulerView()...?
If so, can you achieve your objective by instantiating only once and then using it by reference?
var schedulerView = SchedulerView();
...
Navigator.of(context).push( MaterialPageRoute( builder: (_) => schedulerView));

Flutter/Dart - Edit Page in PageView, then Refresh and Scroll back to Same Place?

Currently, I can submit edits to a single page in a PageView and then either Navigator.push to a newly created single edited page or Navigator.pop back to the original Pageview containing the unedited page.
But I'd prefer to pop back to the the same place in an updated/refreshed Pageview. I was thinking I could do this on the original PageView page:
Navigator.pushReplacement(context,new MaterialPageRoute(
builder: (BuildContext context) => EditPage()),);
But after editing, how can I pop back to a refreshed PageView which is scrolled to the now updated original page? Or is there a better way? Someone mentioned keys, but I've not yet learned to use them.
The question deals with the concept of Reactive App-State. The correct way to handle this is through having an app state management solution like Bloc or Redux.
Explanation: The app state takes care of the data which you are editing. the EditPage just tells the store(App-State container) to edit that data and the framework takes care of the data that should be updated in the PageView.
as a temporary solution you can use an async call to Navigation.push() and refresh the PageView State once the EditPage comes back. you can also use an overloaded version of pop() to return a success condition which aids for a conditional setState().
Do you know that Navigator.pushReplacement(...) returns a Future<T> which completes when you finally return to original context ?
So how are you going to utilize this fact ?
Lets say you want to update a String of the original page :
String itWillBeUpdated="old value";
#override
Widget build(BuildContext ctx)
{
.
.
.
onPressesed:() async {
itWillBeUpdated= await Navigator.pushReplacement(context,new MaterialPageRoute(
builder: (BuildContext context) => EditPage()),);
setState((){});
},
}
On your editing page , you can define Navigator.pop(...) like this :
Navigator.pop<String>(context, "new string");
by doing this , you can provide any data back to the original page and by calling setState((){}) , your page will reflect the changes
This isn't ideal, but works somewhat. First I created a provider class and added the following;
class AudioWidgetProvider with ChangeNotifier {
int refreshIndex;
setRefreshIndex (ri) {
refreshIndex = ri;
return refreshIndex;
}
}
Then in my PageView Builder on the first page, I did this;
Widget build(context) {
var audioWidgetProvider = Provider.of<AudioWidgetProvider>(context);
return
PreloadPageView.builder(
controller: PreloadPageController(initialPage: audioWidgetProvider.refreshIndex?? 0),
Then to get to the EditPage (2nd screen) I did this;
onPressed: () async {
audioWidgetProvider.setRefreshIndex(currentIndex);
Navigator.pushReplacement(context,new MaterialPageRoute(builder: (BuildContext context) => EditPage()),); }
And finally I did this to return to a reloaded PageView scrolled to the edited page;
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) =>HomePage()));
The only problem now is that the PageView list comes from a PHP/Mysql query and I'm not sure what to do if new items are added to the list from the Mysql database. This means the currentIndex will be wrong. But I guess that's the topic of another question.

How to navigate in flutter during widget build?

I'm trying to detect that user is no longer authenticated and redirect user to login. This is how I'm doing it
Widget build(BuildContext context) {
return FutureBuilder(
future: _getData(context),
builder: (context, snapshot) {
try {
if (snapshot.hasError && _isAuthenticationError(snapshot.error)) {
Navigator.push(context, MaterialPageRoute(builder: (context) => LoginView()));
}
Unfortunately doing navigation on build is not working. It throws this error
flutter: setState() or markNeedsBuild() called during build.
flutter: This Overlay widget cannot be marked as needing to build because the framework is already in the
flutter: process of building widgets. A widget can be marked as needing to be built during the build
I cannot just return LoginView widget since parent widget containts app bar and floating button and login view needs to be displayed without these controlls.. I need to navigate.
Is it possible to do it?
Wrap it in Future.microtask. This will schedule it to happen on the next async task cycle (i.e. after build is complete).
Future.microtask(() => Navigator.push(
context,
MaterialPageRoute(builder: (context) => LoginView())
));
Streams in flutter
The usual thing is to use a flow where user changes occur.
When the user logs off, he detects that change and can direct it to another window.
problem here :
snapshot.hasError && _isAuthenticationError(snapshot.error)
Instead of this use OR
snapshot.hasError || _isAuthenticationError(snapshot.error)

Pass context to navigator push to access inherited widget data

I'm trying to access data from an inherited widget placed under the MaterialApp in my tree from a MaterialPageRoute.
When I try to access the data from this route UserModel.of(context).data it say it's null
I get that this is because the UserModel provider should be placed above the whole MaterialApp for it to share the context but it's impossible in my case.
I therefore tried to pass the context from the navigator builder in hope it would give me access to it:
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SettingsScreen(
appContext: context)),
);
}
and then in SettingScreen
UserModel.of(appContext).data
But it didn't work either...
Any idea on how to do this ?
You can just declare a constructor of SettingsScreen and pass your data in constructor. :)