1

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!!!

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

To initialise myModel, you need the context which is inside Widget build(BuildContext context) method. So how do you access it in initState and dispose methods? Can you provide a full example?
If you have initState, it means you are using a StatefulWidget. The State<T> class has a getter context that allows you to access the context in the initState. Just do something like: @override void initState() { super.initState(); final myModel = getMyModelFromContext(context); myModel.addListener(_showDialog); } where getMyModelFromContext is the method you have to get your myModel from the context

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.