Could not find the correct Provider<X> above this Y Widget In Flutter with navigational flows

1,700

Solution 1

When performing navigation using Navigator.of(context) the route you push becomes part of the widget tree of your MaterialApp via its internal default Navigator. However, that route does not become a child of ChangeNotifierProvider but of the MaterialApp.

You should make the provider an ancestor of your MaterialApp.

Solution 2

Move ChangeNotifier above MyApp:

void main() {
  runApp(ChangeNotifierProvider(
      builder: (context) => ContentDS(),
      child: MyApp()));
}
Share:
1,700
Debanjan Chakraborty
Author by

Debanjan Chakraborty

Updated on December 14, 2022

Comments

  • Debanjan Chakraborty
    Debanjan Chakraborty 14 minutes

    I am not unerstanding why the Provider is not being accepted here.

    My main.dart looks like this.

    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          debugShowCheckedModeBanner: false,
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: ChangeNotifierProvider<ContentDS>(
            builder: (_) => ContentDS(),
            child: Content(),
          )
        );
      }
    }
    

    Provider works perfectly in Content Class. Now I move from Content to Content Details using this code

    Navigator.of(ctx).push(MaterialPageRoute(
                    builder: (context) =>
                        ContentDetails(viewedList: listElement),
                  ))
    

    In Content Details, I am just trying to access the Provider again

     final ds = Provider.of<ContentDS>(context);
    

    But this gives me the following error

    Error: Could not find the correct Provider above this ContentDetails Widget

    To fix, please:

    • Ensure the Provider is an ancestor to this ContentDetails Widget * Provide types to Provider * Provide types to Consumer * Provide types to Provider.of() * Always use package imports. Ex: import 'package:my_app/my_code.dart'; * Ensure the correctcontext` is being used.

    Content-Details code

    class ContentDetails extends StatefulWidget {
      ToDoList viewedList;
      ContentDetails({this.viewedList});
      @override
      _ContentDetailsState createState() => _ContentDetailsState();
    }
    class _ContentDetailsState extends State<ContentDetails> with SingleTickerProviderStateMixin{
      bool isOpened = false;
      AnimationController _animationController;
      Animation<Color> _buttonColor;
      Animation<double> _animateIcon;
      Animation<double> _translateButton;
      Curve _curve = Curves.easeOut;
      double _fabHeight = 56.0;
      initState() {
        _animationController =
        AnimationController(vsync: this, duration: Duration(milliseconds: 500))
          ..addListener(() {
            setState(() {});
          });
        _animateIcon =
            Tween<double>(begin: 0.0, end: 1.0).animate(_animationController);
        _buttonColor = ColorTween(
          begin: Colors.blue,
          end: Colors.red,
        ).animate(CurvedAnimation(
          parent: _animationController,
          curve: Interval(
            0.00,
            1.00,
            curve: Curves.linear,
          ),
        ));
        _translateButton = Tween<double>(
          begin: _fabHeight,
          end: -14.0,
        ).animate(CurvedAnimation(
          parent: _animationController,
          curve: Interval(
            0.0,
            0.75,
            curve: _curve,
          ),
        ));
        super.initState();
      }
      @override
      dispose() {
        _animationController.dispose();
        super.dispose();
      }
      animate() {
        if (!isOpened) {
          _animationController.forward();
        } else {
          _animationController.reverse();
        }
        isOpened = !isOpened;
      }
      @override
      Widget build(BuildContext context) {
        final ds = Provider.of<ContentDS>(context);
        print(" ds.count ---> " + ds.count.toString());
        if (widget.viewedList != null){
          debugPrint(" widget.viewedList.primaryID ---> " + widget.viewedList.primaryID);
        }else{
          debugPrint(" It is null");
        }
        return
         Hero(
            tag: (widget.viewedList != null) ? widget.viewedList.primaryID : 'Hero',
            child: Scaffold(
              appBar: new AppBar(
                backgroundColor: ListStatusHelper.getBgGenericColor(widget.viewedList?.status ?? ListStatus.NONE),
                title: Text('${getListTitle()}'),
                elevation: 0.0,
              ),
              floatingActionButton:  Wrap(
                direction: Axis.vertical,
                children: <Widget>[
                  transformWorks(edit(), 3),
                  transformWorks(save(), 2),
                  transformWorks(inbox(),1),
                  toggleButton()
                ],
              ),
              body: Container(
                  color: ListStatusHelper.getBgGenericColor(widget.viewedList?.status ?? ListStatus.NONE),
                  child: const Text("Once Provider is available, need to work on this section");
                ),
              ),
        );
      }
      Widget transformWorks(Widget btn, int pos){
        return Transform(
          transform: Matrix4.translationValues(
            0.0,
            _translateButton.value * pos,
            0.0,
          ),
          child: btn,
        );
      }
      Widget inbox() {
        return Container(
          child: FloatingActionButton(
            heroTag: null,
            onPressed: null,
            tooltip: 'Inbox',
            elevation: 0.0,
            child: Icon(Icons.inbox),
          ),
        );
      }
      Widget edit() {
        return Container(
          child: FloatingActionButton(
            heroTag: null,
            onPressed: null,
            tooltip: 'Edit',
            elevation: 0.0,
            child: Icon(Icons.edit),
          ),
        );
      }
      Widget save() {
        return Container(
          child: FloatingActionButton(
            heroTag: null,
            onPressed: null,
            tooltip: 'Save',
            elevation: 0.0,
            child: Icon(Icons.save),
          ),
        );
      }
      Widget toggleButton(){
        return  FloatingActionButton(
          heroTag: null,
          backgroundColor: _buttonColor.value,
          onPressed: animate,
          tooltip: 'Toggle',
          child: AnimatedIcon(
            icon: AnimatedIcons.menu_close,
            progress: _animateIcon,
          ),
        );
      }
      String getListTitle() {
        if (widget.viewedList != null) {
          return widget.viewedList.listTitle;
        } else {
          return 'New List';
        }
      }
    }
    

    I am an iOS developer who is trying to learn flutter, and I thought that Provider should be available to all classes that belong within a navigational flow, without utilising any DI.

    Help me realise what am I missing. How should Provider be used in case of navigational flows such as aforementioned cases.

    Thanks in advance

    • Andrey Gordeev
      Andrey Gordeev about 3 years
      Please add code of ContentDetails widget
    • Debanjan Chakraborty
      Debanjan Chakraborty about 3 years
      Added the Content Details
    • rstrelba about 3 years
      Why not move up provider class with MaterialApp as child of provider?
    • Debanjan Chakraborty
      Debanjan Chakraborty about 3 years
      So, you mean that the child for ChangeNotifierProvider<ContentDS> will be the material app? How does that solve the problem?