Flutter web: Prevent UI state update on browser window resize - flutter

I have a flutter web page with three dropdown buttons which I use to query the database and show some objects to the user, selecting the dropdown value updates the UI as expected and modifying the variable the API needs to make the query.
The problem comes when the user resizes the browser window, that causes the UI to update again and the dropdown values revert to the default ones.
There is no error message or anything, I just want to keep the state when the screen resizes.
Is there a way for me to prevent that state change when the browser window changes its size?
or do I just let the user see that when the screen size changes, the choices made disappear and they have to select them again?

Few options to do that:
Option 1: (recommended best practice)
the future variable that you use to retrieve from db should be in initState(). This will prevent re-querying when resizing
#override void initState() {
super.initState();
myFuture = _dbService.get(dropDownValues);
}
Option 2:
add a new bool variable isIntendedRebuild that you can set to true in your setState() after the drop down is updated. then, in your build(), add an if to prevent updating of your object if not intended rebuild. Do not forget to set isIntendedRebuild to false at the end of build.
#override Widget build(BuildContext context) {
if (intendedRebuild) {
///update the values of your displayed objects , otherwise dont
}
}

Related

How can I call setState() safely after returning a value from a dialog in Flutter?

Here is the problem: I have a list of items displayed in a list view. I can edit these items with the dialogs displayed by clicking on them. After editing and closing the dialog, I also need to update the items on the list view. I'm currently doing this with the following code snippet in my list view item widget:
showDialog(
context: context,
builder: (context) {
return UpdateItemDialog(item: _item);
},
).then((updatedItem) {
if (updatedItem != null) {
setState(() => _item = updatedItem);
}
});
and by calling Navigator.of(context).pop(_item); from my dialog.
It works perfectly fine when there are no rebuilds occur until the dialog is dismissed. However, for example, if the orientation is changed when the dialog is open, I get Unhandled Exception: setState() called after dispose() error since the list view also rebuilt because of the orientation change and the then clause in my code runs on the destroyed widget.
Is there a way to access the rebuilt widget from a destroyed widget?
Or should I use a different approach to this problem?
By the way, changes should only be accepted after the dialog is dismissed, so I should return the item from the dialog.
I believe your best bet would be to introduce even a simple state management solution (Provider would be good) to handle communication between a dialog and other widgets.
Check out the Gist below (Run it on Dartpad.dev) as an example how you can keep it simple, yet clean and decoupled
https://gist.github.com/romanejaquez/8aed8d699fba8fdfff4b0966dfe47663
in which I show that instead of passing data from a dialog back to another widget, a State Management solution would allow you for a decoupled way of passing data back and forth, notifying each other and triggering rebuilds (which is kind of calling setState() since pretty much that's what you want - trigger a rebuild on the other widget. In this example, I'm sending a value back to the originating widget and triggering a rebuild (thanks to the Consumer widget listening to the changes triggered in the common service. That'd be my honest suggestion.

How to refresh Dialog when the data has change? Flutter

I'm a new Flutter developer and I have a problem, which I haven't been able to solve yet, even if I tried a lot.
I'm developing an App, where at some point a Dialog is opened(with showDialog()). In this Dialog there are 2 AutoCompleteTextField:
In the first one, the data will always be the same. So there is a list and the user needs to choose one of the choices. First AutoCompleteTextField code
In the second one, the data to be shown depends on the previous choice. In other words,
whenever an item from the previous list is chosen, the subdata of the item will be requested. Second AutoCompleteTextField code
The required data is fetched properly, however the dialog is not refreshing state so the suggestions of the second AutoCompleteTextField appears empty. When I close and enter again the suggestions of the second appears as they should.
To get notified when the data changes I use ChangeNotifier and Provider, but doesn´t refresh the Dialog (ChangeNotifier class). I also use StatefulBuilder to be able to use setState, but again, doesn´t refresh (Dialog code).
I would like to know if there is any other way to refresh the Dialog. Thank you!
PD: This is my first question in StackOverflow. I tried my best.
I think you need to use Provider.of(context) to be able to listen to the updates and refresh or add/update the data.
Provider.of(context)
I would create a widget class instead of the _widgetTask function and then use Provider.of(context) inside the widget build function like following (I think you can also try to add it inside the _widgetTask function but I dont know if this would work).
class WidgetTask extends StatelessWidget {
//WidgetTask contructor here..
#override
Widget build(BuildContext context) {
final odooData = Provider.of<OdooData>(context);
And then use the odooData to access the data/functions you need to update/listen to from the provider.
Also you can wrap the widget with GestureDetector so that you can update the widget upon tapping using the OnTap property.
flutterdartdialogrefreshproviderconsumer

Changing state of entire page vs one button in flutter

Ok, I am working on a media player app using flutter. Now when I press the play button, it changes to pause button. (Only the icon on the button changes)
The onPressed function for the button changes a boolean value and calls the setState() method.
It goes something like this.
bool _playing = false;
void _onPlayButtonPressed() {
setState () {
if (_playing)
_playing = false;
else
_playing = true;
}
}
I also have a function that returns the icon based on the value of _playing.
Widget _playButtonIcon() {
//This function has no setState() call
if (_playing)
//return pause icon
else
//return play icon
}
Everything works fine. The icon changes everytime I press the button. However as mentioned in docs and also in Flutter Demo App, setState() method calls the build method. Which redraws the entire widget tree including child widgets that are completely unchanged.
Is this approach justified or is this an overkill?
Do I have to put the button on a different Stateful Widget Class and call its build method via setState() everytime I tap this playButton?
What if I have other widgets that also changes the state of UI. Possibly changing different widgets?
What is the proper way to do this without having a performance hit?
Creating a play button that is a widget of its own with a state that maintains whether it is playing or not definitely makes sense. Now when you call setState on the parent widget it does call the build method, but as far as I know it does not necessarily redraw everything from scratch. If no changes are found in some of the embedded widgets it does not redraw them since they are already in the widget tree. Finally, it is okay to call setstate, however if your app starts getting bigger and you find yourself calling set state in too many places, and want to use global keys, I would advise looking into the Provider package, and making use of the ChangeNotifier/Consumer pattern.

Problem showing a value contained in an InheritedWidget

I've been developing in Flutter for a few months and I'm not yet very experienced. These days I'm working on an app that I didn't create from the beginning and I'm having a strange problem, unfortunately I can't paste too much pieces of code but I try to explain the wrong behavior.
The state of the app is contained in an InheritedWidget that is called before all the others. For example, in this InheritedWidget there is a value that must always be visible at the top of the app (in the AppBar). The problem is that if at runtime this value is changed in the InheritedWidget, the view shows the previous value (as if it wasn't updated), but if I do Navigator.push() to a new page, the AppBar shows the correct value (i.e. the updated one). If I pop to the previous page, the old value reappears in the AppBar. If I put the app in the background and bring it back to the foreground, the correct value finally appears.
It seems that the view does not update even if the value changes in the InheritedWidget. I specify that before being displayed, this value is extracted directly from the InheritedWidget using context.dependOnInheritedWidgetOfExactType<InheritedWidgetName>(). I also specify that "updateShouldNotify" is set this way:
#override
bool updateShouldNotify(Session oldWidget) {
return true;
}
I wanted to ask if anyone knows what might be causing this problem.
Thanks in advance.

Is there a way to tell when a Widget is shown with GWT?

I'd like to respond to an even whenever my widget is made visible on a page done with GWT and UI Binder.
Is there anything similar to the onAttach() event handler (which fires when the widget is added to the DOM), pertaining to when the widget is actually made visible?
I'd like to be able to handle the even when the widget is shown because there are a few different ways of making it visible, and I'd like a single place on the widget itself that can handle this event.
Thanks
I know this is an old question, I have faced the same problem before. What I did was override the setVisible(boolean visible) method in the widget, then perform whatever I needed to do:
#Override
public void setVisible(boolean isVisible) {
super.setVisible(isVisible);
if(isVisible) {
// Do whatever you need to do with your widget
}
}
The widget should be visible once added to the DOM unless you've intentionally hidden it (i.e. with CSS or hid it behind another widget). Normally, onAttached() means its on the page. If you're using CSS classes to make it visible, write a setVisible(boolean isVisible) method to your widget and set the visibility class this way. If you have it behind another widget (i.e. in layers) then you'll need to write your only logic to determine when it's visible.
There is no browser event for this, but you could try this:
With your widget you could check the elements getLeftOffset (or similar method), if you get a positive value, you could fire your method, and set a flag to indicate that your onVisible() method had fired.
Then once the getLeftOffset returns a 0 you could reset your flag, ready to fire your event again.