8

Currently its very hectic to show dialog from any layer of code in app just because one has to pass context in it. Hence i thought to pass navigatorKey.currentContext (Navigator key is a global key passed to Material app navigatorKey parameter) to show dialog. But i got the error

"Navigator operation requested with a context that does not include a Navigator.The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget."

The issue is showDialog calls Navigator.of(context) internally and which looks for the navigator ancestor which ofcourse will return null as the navigator is itself the root. Hence it will not find the navigator as ancestor.

Is there a way we can directly pass the navigator state/context to showDialog function to show the dialog? Or is there a more easy way to show Dialog without passing context to it if we want to show it from bloc?

Ayush P Gupta
  • 1,459
  • 1
  • 17
  • 24

4 Answers4

10

I found a simple solution:

navigatorKey.currentState.overlay.context

I use this in a redux middleware where I keep navigatorKey, and want to show a dialog globally anywhere in the app everytime I dispatch a specific action.

KLD
  • 124
  • 1
  • 4
6

Since this one is merged: https://github.com/flutter/flutter/pull/58259

You can use:

navigatorKey.currentContext;
Sander Roest
  • 839
  • 6
  • 10
1

You can make use of InheritedWidget here. Make a InheritedWidget the root for your application which holds a navigator key. Then you can pass any context of child widgets to get the current navigator state.

Example:

InheritedWidget:

// Your InheritedWidget
class NavigatorStateFromKeyOrContext extends InheritedWidget {
  const NavigatorStateFromKeyOrContext({
    Key key,
    @required this.navigatorKey,
    @required Widget child,
  }) : super(key: key, child: child);

  final GlobalKey<NavigatorState> navigatorKey;

  static GlobalKey<NavigatorState> getKey(BuildContext context) {
    final NavigatorStateFromKeyOrContext provider =
        context.inheritFromWidgetOfExactType(NavigatorStateFromKeyOrContext);
    return provider.navigatorKey;
  }

  static NavigatorState of(BuildContext context) {
    NavigatorState state;
    try {
      state = Navigator.of(context);
    } catch (e) {
      // Assertion error thrown in debug mode, in release mode no errors are thrown
      print(e);
    }
    if (state != null) {
      // state can be null when context does not include a Navigator in release mode
      return state;
    }
    final NavigatorStateFromKeyOrContext provider =
        context.inheritFromWidgetOfExactType(NavigatorStateFromKeyOrContext);
    return provider.navigatorKey?.currentState;
  }

  @override
  bool updateShouldNotify(NavigatorStateFromKeyOrContext oldWidget) {
    return navigatorKey != oldWidget.navigatorKey;
  }
}

HomeScreen:

// Your home screen
class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      navigatorKey: NavigatorStateFromKeyOrContext.getKey(context),
      home: InitPage(),
    );
  }
}

The root of the application will look like,

final GlobalKey navigator = GlobalKey<NavigatorState>(debugLabel: 'AppNavigator');

runApp(
  NavigatorStateFromKeyOrContext(
    navigatorKey: navigator,
    child: HomePage(),
  ),
);

Now from anywhere in the app, pass any context to get the NavigatorState like

NavigatorStateFromKeyOrContext.of(context)

Note: This is one approach I came up with where I used InheritedWidget, there are many other ways to achieve the same, like using Singleton, having a global bloc to provide navigator key, storing the navigator key in a Redux store or any other global state management solutions, etc.

Hope this helps!

Hemanth Raj
  • 32,555
  • 10
  • 92
  • 82
  • see the issue isnt of accessing navigator key. This i can easily access by just making it a top-level function or simply static. The trouble is the context return by navigatorKey.currentState doesnt contain Navigator as ancestor as it itself the navigator only – Ayush P Gupta Mar 16 '19 at 16:11
  • Yes I understand that perfectly. That happens when the context you pass has no `Navigator` as parent, i.e either your app is not a `MaterialApp` or you do not have a `Navigator` parent to that child somewhere top in the tree. This should give access to navigator without any error that you are currently getting. Please try this, or at least post some code of how you are using it. It'll be helpful to resolve. Thanks :) – Hemanth Raj Mar 17 '19 at 06:09
-1

Currently, I am showing a dialog by creating a function in my util class which takes the context as a parameter.

static void showAlertDialog(String title, String message, BuildContext context) { // flutter defined function showDialog( context: context, builder: (BuildContext context) { // return object of type Dialog return AlertDialog( title: new Text(title), content: new Text(message), actions: <Widget>[ // usually buttons at the bottom of the dialog new FlatButton( child: new Text("Close"), onPressed: () { Navigator.of(context).pop(); }, ), ], ); }, ); }

Using the above function as: UtilClass. showAlertDialog("Title", "Message", context);

somnath121
  • 21
  • 4
  • 2
    See the issues was to pass context in dialog not the way to show dialog. Please tell me a way to pass context without actually passing context to this method every time – Ayush P Gupta Mar 16 '19 at 03:33