Home > OS >  How to open a Dialog in flutter when a value changes in a ChangeNotifierProvider
How to open a Dialog in flutter when a value changes in a ChangeNotifierProvider

Time:05-10

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.

  • Related