116

I am new in Flutter and I am trying receive data with a Dialog. When a click in textField the error of image2 appear...

Layout's Image Error's Image

show(BuildContext context){

    var dialog = Dialog(
      child: Container(
        margin: EdgeInsets.all(8.0),
        child: Form(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              TextFormField(
                decoration: InputDecoration(
                    labelText: "Insira o número de telefone",
                    border: OutlineInputBorder(
                        borderRadius: BorderRadius.all(Radius.circular(2.0)))),
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.end,
                children: <Widget>[
                  FlatButton(
                      onPressed: () {
                        Navigator.of(context).pop();
                      },
                      child: Text("Cancelar")),
                  FlatButton(
                      onPressed: () {
                        Navigator.of(context).pop();
                      },
                      child: Text("Aceitar"))
                ],
              )
            ],
          ),
        ),
      ),
    );

    showDialog(context: context,builder: (context){
      return dialog;
    });
  }

This is my code.

I/flutter (31032): Looking up a deactivated widget's ancestor is unsafe.
I/flutter (31032): At this point the state of the widget's element tree is no longer stable. To safely refer to a
I/flutter (31032): widget's ancestor in its dispose() method, save a reference to the ancestor by calling
I/flutter (31032): inheritFromWidgetOfExactType() in the widget's didChangeDependencies() method.
I/flutter (31032): 
a2x
  • 1,261
  • 2
  • 6
  • 4

20 Answers20

106

Declare a global variable

    final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();

then register the key on your widget build's scaffold eg

    @override
    Widget build(BuildContext context) {
     return Scaffold(
       key: _scaffoldKey,
       ...

then on the dialog

show(BuildContext context){

var dialog = Dialog(
  child: Container(
    margin: EdgeInsets.all(8.0),
    child: Form(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          TextFormField(
            decoration: InputDecoration(
                labelText: "Insira o número de telefone",
                border: OutlineInputBorder(
                    borderRadius: BorderRadius.all(Radius.circular(2.0)))),
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.end,
            children: <Widget>[
              FlatButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: Text("Cancelar")),
              FlatButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: Text("Aceitar"))
            ],
          )
        ],
      ),
    ),
  ),
);

Pass that scaffold context to the showDialog method

showDialog(context: _scaffoldKey.currentContext ,builder: (context){
  return dialog;
 });
}
Felix Runye
  • 2,135
  • 1
  • 20
  • 20
  • 1
    thanks! this helped me with one of my dialogs, but i have another page which whenever loggs in successfully i pop using ```navigator.of(context)..pop()..pop()..pop("yes")``` but when dialog is shown i face this error, i used a scaffold key and also the builder. – Mahdi-Jafaree Oct 18 '20 at 06:19
  • This works for me having a big calling project.. which has multiple roles types .. passing scaffold.currentContext! has solved the issues as I was using the function for multiple roles of pages. Kudos to solution !! – neon97 Aug 06 '21 at 11:42
  • 10
    Thanks for the answer! Can you explain why this works a bit? – batuhankrbb Aug 17 '21 at 03:54
  • 2
    ``Navigator.of(_scaffoldKey.currentContext!).pop();`` to close dialog – Mod May 19 '22 at 03:52
70

Try This

Give different context name for dialog

 showDialog(context: context,builder: (dialogContex){
              return Dialog(
                child: Container(
                  margin: EdgeInsets.all(8.0),
                  child: Form(
                    child: Column(
                      mainAxisSize: MainAxisSize.min,
                      children: <Widget>[
                        TextFormField(
                          decoration: InputDecoration(
                              labelText: "Insira o número de telefone",
                              border: OutlineInputBorder(
                                  borderRadius: BorderRadius.all(Radius.circular(2.0)))),
                        ),
                        Row(
                          mainAxisAlignment: MainAxisAlignment.end,
                          children: <Widget>[
                            FlatButton(
                                onPressed: () {
                                  Navigator.of(dialogContex).pop();
                                },
                                child: Text("Cancelar")),
                            FlatButton(
                                onPressed: () {
                                  Navigator.of(context).pop();
                                },
                                child: Text("Aceitar"))
                          ],
                        )
                      ],
                    ),
                  ),
                ),
              );
            });
Savad
  • 1,513
  • 12
  • 17
  • 2
    this answer is technically right as we need to remove dialog so we should give diffrent name to dialog context – Dhananjay pathak Dec 23 '21 at 05:37
  • 1
    Exactly what I was looking for. I have a dialog with edit text fields and also a loading dialog, naming the contexts separates them and I am able to close both successfully! – Francois Mar 20 '23 at 14:03
  • You can create a buildContext variable and assign context to it. Then you can pass that newly created variable to showDialog method. – san88 May 12 '23 at 11:13
27

I got the same error when attempting to open a dialog and I found a solution here: github flutter issues. Specifically, I followed the poster's recommendation, which was to create a GlobalKey and associate it with the Scaffold widget, and use the context from that key when creating the dialog. In my case, I have a globally accessible object which holds the GlobalKey:

MyGlobals myGlobals = MyGlobals();
class MyGlobals {
  GlobalKey _scaffoldKey;
  MyGlobals() {
    _scaffoldKey = GlobalKey();
  }
  GlobalKey get scaffoldKey => _scaffoldKey;
}

In the Scaffold widget constructor call:

Scaffold(
  appBar: ...,
  body: ...,
  drawer: ...,
  key: myGlobals.scaffoldKey,
)

And in the showDialog call:

showDialog<String>(
  barrierDismissible: ...,
  builder: ...,
  context: myGlobals.scaffoldKey.currentContext,
);
Andy King
  • 1,632
  • 2
  • 20
  • 29
  • @ajs.sonawane Do you mean that it doesn't work when you create a dialog from within a dialog, or it doesn't work when you try to use it a second time with the same dialog, or that it doesn't work if you use it for one dialog, close that dialog, and then open a different dialog? – Andy King Jul 11 '20 at 17:17
  • 2
    nope, calling dialog then popping it and then calling it again – ajs.sonawane Jul 11 '20 at 18:03
  • @ajs.sonawane It seems to be working for my situation ... perhaps you will need to post a new question. Sorry. – Andy King Jul 12 '20 at 06:19
20

You’re trying to access a context that isn’t probably available. That happens because you’ve assigned your Dialog to a var and afterwards use a different context (the one from your dialog builder).

Either create your dialog directly after your return in the builder or make it a method instead that returns a Dialog and pass it a BuildContext parameter.

Widget myDialog(BuildContext context) => Dialog(/*your dialog here*/);

This is also a more convenient Flutter practice. You should use methods that return widgets instead of assigning it to variables.

Miguel Ruivo
  • 16,035
  • 7
  • 57
  • 87
  • You need to provide more code context/info then. At first glance that's what it seems, because when you are popping the `Dialog` you may be referring to an invalid widget context. – Miguel Ruivo Feb 10 '19 at 23:01
  • 2
    This is **not** a convenient flutter practice. See https://stackoverflow.com/a/53234826/10122791 – Augustin R Nov 25 '19 at 09:00
19

use this:

Navigator.of(context,rootNavigator: true).pop();

instead of

Navigator.of(context).pop();
Biruk Telelew
  • 1,161
  • 7
  • 13
  • 5
    Can you elaborate a bit on this? Why / in which cases is the latter preferable? – dgilperez Apr 09 '21 at 13:05
  • For Explaination please visit : https://stackoverflow.com/questions/60349741/what-is-the-use-of-rootnavigator-in-navigator-ofcontext-rootnavigator-true – Sayed Muhammad Idrees Nov 16 '21 at 18:59
  • This will not necessarily help. If your context is outdated, this might still fail, as even with the `rootNavigator: true` part you are still accessing a `BuildContext` that is no longer viable. Also: you might discover unwanted navigation behaviour, e.g., when you use tab bars. – Matthias Schicker May 27 '22 at 12:34
9

This might happen while you are popping from the context and trying to open new content on the context you are popping.

()async{
    Navigator.of(context).pop();
    _alertPopUp(); // shows a dialog
    // might do some work after
}

if alert dialog is created on current context then it throws an error because context doesn't exist anymore

Pang
  • 9,564
  • 146
  • 81
  • 122
enumerator
  • 167
  • 2
  • 2
4

My problem was that I was using hot reload for pretty long time, I think at some point everything got messed up, doing a normal run of the app fixed the problem.

Ray Rojas
  • 151
  • 1
  • 8
2

removing application from emulator and run below commands

flutter clean
flutter pub get 

works for me

mayfall
  • 41
  • 5
2

I had the same bug, but in totally different context. I use Riverpod as a state manager, and I wanted to cancel a stream in StatefulWidget dispose method. It turned out that it caused this bug. What I had to do is to use Riverpod's onDispose API.

ref.onDispose(() {
    batteryStateSubscription.cancel();
});

A full example is shown in the documentation

PrzemekTom
  • 1,328
  • 1
  • 13
  • 34
1

Though you got desired answer, just for better clarification for others I put my opinion here.

Reason : It is happend due to context mismatch issue. Your passing context to Navigator.of(context).pop() is not matching with your MainApp BuildContext.

Solution : There has 2 way

  1. U can use Global key
  2. pass actual context to your Navigator

Below link I already mentioned how to solve this by passing actual context

https://stackoverflow.com/a/73543251/6109034

Mimu Saha Tishan
  • 2,402
  • 1
  • 21
  • 40
1

Use this if You are using Stack in AlertDialog Not Closing on Navigator.of(context).pop();

late NavigatorState _navigator;

   @override
  void didChangeDependencies() {

    _navigator = Navigator.of(context);

    super.didChangeDependencies();
}

Use This

 Positioned(right: 10.0,child: GestureDetector(

                  // behavior: HitTestBehavior.translucent,

                  onTap: () {
                    _navigator.pop(context);
                    },
                  child: Align(
                    alignment: Alignment.topRight,
                    child: CircleAvatar(
                      radius: 14.0,
                      backgroundColor: Colors.white,
                      child: Icon(Icons.close, color: black),
                    ),
                  ),
                ),
              ),
Kush Patel
  • 1,228
  • 1
  • 13
  • 34
0

Try this:

    Future<AlertDialog> myDialog(BuildContext context) {
    return showDialog<AlertDialog>(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          content: Container(
            margin: EdgeInsets.all(8.0),
            child: Form(
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  TextFormField(
                    decoration: InputDecoration(
                        labelText: "Insira o número de telefone",
                        border: OutlineInputBorder(
                            borderRadius:
                                BorderRadius.all(Radius.circular(2.0)))),
                  ),
                ],
              ),
            ),
          ),
          actions: <Widget>[
            FlatButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: Text("Cancelar")),
            FlatButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: Text("Aceitar"))
          ],
        );
      },
    );
  }
Fellipe Malta
  • 3,160
  • 1
  • 7
  • 12
0

declare dialog and set in initState

  late Dialog dialog;

  @override
  void initState() {
    super.initState();

    dialog = Dialog(
      ...
    );
  }
Linar
  • 903
  • 6
  • 10
0

before calling a dialog when a page is just loading, call it by adding SchedulerBinding to it, call it like this

SchedulerBinding.instance?.addPostFrameCallback((_) => showDialog( context: context, barrierDismissible: false, builder: (context) { return dialogBox(context, "Fetching account data", 'Profile page', DialogType.processing, function: () {}, dismissText: "", ); }));

0

In my case I was using a provider where I used a context as an argument to a function, the thing was that when I passed that page I did it with pushnamedAndRemove Until then on the next page I was trying to use a function where I required the above context, so the error was mine because it was trying to get a parameter that I destroyed earlier, for that reason it didn't work. So be careful if you are deleting old pages.

0

calling Navigator.pop(context) at the beginning of async function worked for me.

anas
  • 1
0

First let's understand what the framework is saying:

Point - 1:

Looking up a deactivated widget's ancestor is unsafe. At this point the state of the widget's element tree is no longer stable.

This simply means that the widget(parent of Dialog) is no longer present in the widget tree and it can be confirmed by checking the result of context.mounted property. This can be solved by providing a valid BuildContext to the child just by wrapping the Dialog with a Builder class. You can refer this answer to understand the significance of Builder.

show(BuildContext context){
var dialog = Dialog(
  child: Container(
    margin: EdgeInsets.all(8.0),
    child: Form(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          TextFormField(
            decoration: InputDecoration(
                labelText: "Insira o número de telefone",
                border: OutlineInputBorder(
                    borderRadius: BorderRadius.all(Radius.circular(2.0)))),
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.end,
            children: <Widget>[
              FlatButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: Text("Cancelar")),
              FlatButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: Text("Aceitar"))
            ],
          )
        ],
      ),
    ),
  ),
);

showDialog(
   context: context,
   // Wrapping the clild widget (dialog) within a Builder class.
   builder: (context) => Builder(
     builder: (context) {
      return dialog;
      },
    ),
  );
 }

Point - 2:

To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling inheritFromWidgetOfExactType() in the widget's didChangeDependencies() method.

This simply asks us to save the context(reference to the parent widget) before it gets de-activated. The suggestions to use GlobalKey in the above answers simply does the same. As GlobalKey is unique throughout the application, the context is preserved. However, one can also save the context using state management.

O'Prime
  • 1
  • 1
-1

I simply solved this by wrapping the showDialog with a Builder widget, though for me the error came from a stream builder I simply wrap the stream builder with a builder widget and the remove the notify listeners from the a stream am calling in the stream builder, but in your case wrap the showDialog with a Builder widget and it will use the context from the builder, problem solved

-1

first : declare a FormKey.

 GlobalKey<FormState>myFormKey=GlobalKey<FormState>();

second : add the FormKey to your Form widget.

Form( 

 key:myFormKey,

 child:child

 )
-3

In my case i was calling

setState(() {
   Navigator.pop(context);
});
Ravindra S. Patil
  • 11,757
  • 3
  • 13
  • 40
Muhammad Kashif
  • 253
  • 3
  • 6