user2233706
user2233706

Reputation: 7225

Unable to access Provider in new page route Widget

I am unable to access the Provider in a Widget that I pushed onto the current Navigator:

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:provider/provider.dart';


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

class MyModel with ChangeNotifier {
  String a = 'Test1';
  String b = 'Test2';
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {    

    return MaterialApp(
        title: 'Flutter Demo',
        home: ChangeNotifierProvider(
            create: (context) => MyModel(),
            child: MyHomePage()
        )
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  @override
  Widget build(BuildContext context) {    

    return Consumer<MyModel>(
        builder: (context, myModel, child) =>
            Scaffold(
              appBar: AppBar(
                title: Text(myModel.a),
              ),
              floatingActionButton: FloatingActionButton(
                onPressed: () =>
                    Navigator.of(context).push(
                        PageRouteBuilder(
                            pageBuilder: (context, animation, secondaryAnimation) => Page2(),
                        ),
                    ),
                tooltip: 'Press',
                child: Icon(Icons.add),
              ),
            )
    );
  }
}

class Page2 extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    var myModel = Provider.of<MyModel>(context); // A

    return Scaffold(
              appBar: AppBar(
                title: Text(myModel.b),
              ),
            );
  }
}

I get this error:

The following ProviderNotFoundException was thrown building Page2(dirty):
Error: Could not find the correct Provider<MyModel> above this Navigator Widget

The issue seems to be that the BuildContext object in the Page2 widget is not the same BuildContext that's associated with the Provider. If I pass a reference of original context to Page2 and use that at point (A), everything works, but this doesn't seem to be a good way of solving this problem.

I tried the solution here, by using Navigator.of(context, rootNavigator: true).context as the context inside the build method of Page2, but I still get the same exception.

Upvotes: 5

Views: 4191

Answers (2)

HannesH
HannesH

Reputation: 986

you need to pass the model to the next route, since the provider is scoped to a route by default

do like:

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (newcontext) => 
      ChangeNotifierProvider<YourModel>.value(
        value: Provider.of<YourModel>(context),
        child: newView,
      )
    ),
);

Upvotes: 4

Khadga shrestha
Khadga shrestha

Reputation: 1180

Yo must pass provider in root widget such that you can access from any where when you navigate to another page the model is not available so you must pass the provider to the parent of MaterialApp as

 import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:provider/provider.dart';

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

class MyModel with ChangeNotifier {
  String a = 'Test1';
  String b = 'Test2';
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => MyModel(),
      child: MaterialApp(title: 'Flutter Demo', home: MyHomePage()),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Consumer<MyModel>(
        builder: (context2, myModel, child) => Scaffold(
              appBar: AppBar(
                title: Text(myModel.a),
              ),
              floatingActionButton: FloatingActionButton(
                onPressed: () => Navigator.of(context).push(
                  PageRouteBuilder(
                    pageBuilder: (context, animation, secondaryAnimation) =>
                        Page2(),
                  ),
                ),
                tooltip: 'Press',
                child: Icon(Icons.add),
              ),
            ));
  }
}

class Page2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var myModel = Provider.of<MyModel>(context); // A

    return Scaffold(
      appBar: AppBar(
        title: Text(myModel.b),
      ),
    );
  }
}

Upvotes: 8

Related Questions