Flutter can't change route because undefined name context with PopupMenuButton how to solve?

1,539

Here you have :

MyApp    <------ context
  --> MaterialApp
   (--> Navigator built within MaterialApp)
      --> Scaffold
        --> App Bar
          --> ...

So when you're using the context to find the Navigator, you're using a context for the MyApp which isn't under the navigator. so we can either make a new Stateless or Stateful Widget subclass to contain your Scaffold, as the build function within those will point at that level instead, or we can use a Builder and define the builder callback (which has a context pointing at the Builder) to return the Scaffold.

Working Code we created new subclass - HomeScreen :

import 'package:flutter/material.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final title = 'MyTitle';
    return MaterialApp(
      title: title,
      home: HomeScreen(title),
    );
  }
}

class HomeScreen extends StatelessWidget {
  final String title;

  HomeScreen(this.title);

  final List<Choice> choices = const <Choice>[
    const Choice(title: 'Settings', icon: Icons.settings),
    const Choice(title: 'Log out', icon: Icons.exit_to_app),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(title),
          actions: <Widget>[
            PopupMenuButton<Choice>(
              onSelected: (val) => onItemMenuPress(val, context),
              itemBuilder: (BuildContext context) {
                return choices.map((Choice choice) {
                  return PopupMenuItem<Choice>(
                      value: choice,
                      child: Row(
                        children: <Widget>[
                          Icon(
                            choice.icon,
                          ),
                          Container(
                            width: 10.0,
                          ),
                          Text(
                            choice.title,
                          ),
                        ],
                      ));
                }).toList();
              },
            ),
          ],
        ),
        body: Text("Hello world"));
  }

  void onItemMenuPress(Choice choice, BuildContext context) {
    if (choice.title == 'Log out') {
      print("Logout");
      Navigator.push(
          context, MaterialPageRoute(builder: (context) => LogoutRoute()));
    }
  }
}

class Choice {
  const Choice({this.title, this.icon});

  final String title;
  final IconData icon;
}

class LogoutRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Logout"),
      ),
      body: Center(
        child: Text("Screen"),
      ),
    );
  }
}
Share:
1,539
Francesco Romano
Author by

Francesco Romano

Updated on December 09, 2022

Comments

  • Francesco Romano
    Francesco Romano over 1 year

    I want to click an item menu (PopupMenuItem) and go to another route using Navigator.push but context is undefined inside the method.

    import 'package:flutter/material.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
    
      final List<Choice> choices = const <Choice>[
        const Choice(title: 'Settings', icon: Icons.settings),
        const Choice(title: 'Log out', icon: Icons.exit_to_app),
        ];
    
    
    
      @override
      Widget build(BuildContext context) {
        final title = 'MyTitle';
    
        return MaterialApp(
          title: title,
          home: Scaffold(
            appBar: AppBar(
              title: Text(title),
              actions: <Widget>[
                    PopupMenuButton<Choice>(
                      onSelected: onItemMenuPress,
                      itemBuilder: (BuildContext context) {
                        return choices.map((Choice choice) {
                          return PopupMenuItem<Choice>(
                              value: choice,
                              child: Row(
                                children: <Widget>[
                                  Icon(
                                    choice.icon,
                                  ),
                                  Container(
                                    width: 10.0,
                                  ),
                                  Text(
                                    choice.title,
                                  ),
                                ],
                              ));
                        }).toList();
                      },
                    ),
                  ],
            ),
            body: Text("Hello world")
          ),
        );
    
      }
    
        void onItemMenuPress(Choice choice) {   
          if (choice.title == 'Log out') {
            print("Logout");
            Navigator.push(context, MaterialPageRoute(builder: (context) => LogoutRoute()));
          } 
      }
    
    }
    
    class Choice {
      const Choice({this.title, this.icon});
    
      final String title;
      final IconData icon;
    }
    
    class LogoutRoute extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text("Logout"),
          ),
          body: Center(
            child: Text("Screen"),
          ),
        );
      }
    }
    

    I have tried to pass a context in onItemMenuPress in this way:

    void onItemMenuPress(Choice choice, BuildContext context)
    

    but:

    onSelected: onItemMenuPress(context)
    

    is not working.

    Neither this approach works:

    onSelected: (Choice c) { Navigator.push(context, MaterialPageRoute(builder: (context) => LogoutRoute())); }
    

    I was following this tutorial: https://medium.com/flutter-community/building-a-chat-app-with-flutter-and-firebase-from-scratch-9eaa7f41782e

    and there is a snippet of his code (similar to mine) that seems to work for him: https://github.com/duytq94/flutter-chat-demo/blob/master/lib/main.dart

    I refer to line 235 (onSelected) and lines 199-205 (actual onItemMenuPress method)

    How is it possible? How can I salve? Thanks