[![enter image description here][2]][2]
he problem is that the view do not get the updated data
The process flows like this
Data is fetched by loadData and put it into transactionTypeList of the viewmodel
Print the length of the list inside the load
i had another function which is also called from init to print the length of the list here i get the list
but when i try to get the same data from the builder, the builder receives a blank
Call notifyListener() instead of ChangeProvider().
And give more code if this doesn't solve.
You are not awaiting for your _model.loadData() method, so you can see that although it is called at the first of initState(), the print statement of loadData() is printed at last.
So, you need to await for loadData(), which you cannot do in initState(), and until the loadData() method is completed you need to show a loader in your build method.
Related
for example I have 4 future builder in one screen. All of them returns CircularProgress indicator when they are still waiting for the data. In this case my screen gets full of circular progress indicator. Instead of this I want to show loading screen until all of the FutureBuilders gets their data. What is the correct way to handle this ?
The correct way is to wrap the tasks of those 4 futures into one and wait for them to finish using await sequentially, after last await you can simply hide your loader.
If your requirement is different and you can't wait for all 4 task synchronously. You can have an array of int(data type doesn't matter).
and simply initialise it with 4 elements, remove first element on finishing task from future builder.
List<int> _taskList = [0,1,2,3];
remove when one of the future finishes
_taskList.removeAt(0);
Use one Loader Widget in parent with condition
[if(_taskList.length >= 1) Loader(),]
For asynchronous transactions you've to manage some kind of ledger. Preferred way is using await
I used the BLOC architecture inside my app. One method inside my bloc resolves a picked address-ID from a listView and return the city name. After this I want my Text-Editing-Controller to have this picked value and show it on the texteditingfield:
The BlocA uses a simple ID and look it up using Google-Places API. BlocA then return a new state with the resolved address as a state property. Running the code below did not show the correct city after tapping on a listView-item.
Await do not work unfortunately.
// ListView.builder code
onTap: () {
context
.read<BlocA>()
.add(PickAddress(id: state.searchResults[index].placeId));
FocusScope.of(context).unfocus(); //hide Keyboard
_textController.value = TextEditingValue(text: state.address.city);
the code its not clear enough
remember to use "await" you have to set Async on onTap like this
onTap: () async { ....
if you did that and still not working send the whole code
Do you know what your Bloc actually returns? Use the debugger and step through your code to see what actually happens in your code.
When it comes to using Bloc's to build your state you usually don't access the state with by calling .state.
The line _textController.value = TextEditingValue(text: state.address.city); is not the way you access your state. When the Bloc sends the new state, the widget will rebuild and render based on the new state.
I just started learning Flutter, and I'm going through the Udemy course "Flutter & Dart - The Complete Guide". In that course, there is a section about building a shopping app, which uses providers. In one instance of that app, where the user swipes to delete a product from the Cart page (or screen/route) with the help of the Dismissible widget, he uses a function inside the provider class, which takes a product ID, to delete the item from the cart.
Here is the thing that I don't understand. The Dismissible widget is connected to the provider via this code in the onDismissed property (which fires after the swipe):
Provider.of<Cart>(context, listen: false).removeItem(productId);
And it all works just fine like this. But if you remove the listen parameter (hence turning it into it's default state which is true), then the Dismiss animation still takes place, but the removeItem() method doesn't work, and the cart still stays the same.
Why does this happen?
When we use listen: false we are telling to not rebuild the widget after we remove an item, but they know that we are removing an item so we don't need to listen any value here it's just doing the action of removing
I'll refer to the method Provider.of(context, listen: true) as x throughout this answer.
x is expected to be used ONLY for properties of a Widget that is
expected to change; and
can be rebuilt. For example:
SizedBox(
width: Provider.of<MyLogic>(context, listen: true).width,
)
When used this way, x will ONLY be called when the context owner is being built/rebuilt.
To ensure that it is being used properly, x performs a sanity check every time it is called, making sure that the owner of the context you passed is actually being built/rebuilt. When you call x from within your onPressed or whatever method it is you call it from, x sees that the context owner is not in the "build" phase, and throws this error.
There are a few more details to this, but you don't actually need to know more about it (especially you're just beginning) unless you want to contribute to the package, in which case you should read their documentation.
Side note: you can now use context.watch() and context.read() instead of Provider.of().
Im using the Provider/ChangenNotifier Pattern to handle state as described in the official docs.
I have a state field which I want to set after a Widget is build. However if I try to set in in the build method. I get an Error:
setState() or markNeedsBuild() called during build.
Where can I call something like:
var state = Provider.of<StateModel>(context);
state.field = 'new Val';
You can not set the state during a build, if you want to test a change of state, put this code state.field = 'new Val'; inside a button event, like FloatActionButton or a event after build completed (with Future.delayed or add post fram callback, see Is there any callback to tell me when "build" function is done in Flutter?)
Warning If you are invoking notifyListeners() inside your state.field set, and listening changes in your widget with provider, It would cause an infinite cycle of rebuild... this is another reason that you can not set state during build...
Sometimes an event (eg upload) starts async while the user is on one page. If they navigate away from that page the task's .then(...) will try to display the result on the page which is no longer visible, eg by means of a toast.
How can I get the context of the currently visible page at the time when the Future completes to display a snackbar, toast or dialog?
EDIT:
I see in the description of oktoast (https://pub.dev/packages/oktoast) that version 2 "Does not need the buildContext to be passed", and further
Quote:
Explain #
There are two reasons why you need to wrap MaterialApp
Because this ensures that toast can be displayed in front of all other
controls Context can be cached so that it can be invoked anywhere
without passing in context
This implies to me that there is a better way by providing a Material app ancestor somewhere....
For a simple Solution I would use the Provider Package. Keyword here is StateManagement (https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple)
The Model would look sth like this:
class UploadModel extends ChangeNotifier {
final bool loading = false;
void uploadXY() async{
loading = true;
// This call tells the widgets that are listening to this model to rebuild.
notifyListeners();
await realUploadStuff();
loading = true;
notifyListeners();
}
}
To start the upload:
Provider.of<UploadModel>(this).uploadXY()
To react if loading-bool changes:
if(Provider.of<UploadModel>(this).loading)...
You can find a simple Example here:
https://github.com/flutter/samples/blob/master/provider_counter/lib/main.dart