I have a screen that is using values from a ChangeNotifierProvider
to display the content of the screen. As expected when these values change the screen build method is triggered and the screen content is updated.
I would like that if one of those values changes from false
to true
, a Dialog is opened on that screen.
The only way I figured out to open this Dialog is by launching it from the build method when the value has changed and a new build is called.
I know that the showDialog
is an async method while build is sync and it is an antipattern to manage these side effects from inside the build method. I cannot know when the build method will be called and this could lead to having several dialogs opened everytime the build is called.
So, so far I can only open the dialog from the build method and using a boolean flag in memory to control if the Dialog is opened or not. Like this:
class MyScreen extends StatefulWidget {
const MyScreen();
@override
State<StatefulWidget> createState() => _MyScreenState();
}
class _MyScreenState extends State<MyScreen> {
late final myModel = Provider.of<MyModel?>(context);
bool _isDialogShowing = false;
@override
void initState() {
super.initState();
...
}
void _showMyDialog(BuildContext ctx) {
showDialog(
context: ctx,
barrierDismissible: false,
builder: (context) => AlertDialog(
content: const Text("Hello I am a dialog"),
),
).then((val) {
// The dialog has been closed
_isDialogShowing = true;
});
}
@override
Widget build(BuildContext context) {
// Open dialog if value from `ChangeNotifierProvider` has changed
if (myModel?.hasToShowDialog == true && _isDialogShowing == false) {
_isDialogShowing = true;
Future.delayed(
Duration.zero,
() {
_showMyDialog(context);
},
);
}
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
.....
],
),
],
);
}
}
Do you know how to properly trigger the dialog opening event when a value changes in the ChangeNotifierProvider
? Thank you very much!!!
CodePudding user response:
What you can do is to add a listener to your ChangeNotifier
:
late final myModel = Provider.of<MyModel?>(context);
bool _isDialogShowing = false;
@override
void initState() {
super.initState();
myModel.addListener(_showDialog);
}
@override
void dipose() {
myModel.removeListener(_showDialog);
super.dispose();
}
Future<void> _showDialog() async {
if (_isDialogShowing || !mounted) return;
// `hasToShowDialog` could be a getter and not a variable.
if (myModel?.hasToShowDialog != true) return;
_isDialogShowing = true;
await showDialog(
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
content: const Text("Hello I am a dialog"),
),
);
_isDialogShowing = false;
}
I don't know what your MyModel
looks like so it is hard to know what else you could fo. hasToShowDialog
could be a getter and not a variable as you suggested in your question.