'Provider: create new model object per each sequence of pages

I am new to Provider. I am trying to use the provider model across multiple pages.

I have 2 sequence of pages. In the first sequence, there is only one page IncrementerPage, which will just increment the count. In the second sequence, there is an OptionsPage, which will display the count value and has 2 option buttons(Increment & Decrement). By clicking these buttons will navigate to corrensponding pages IncrementerPage & DecrementerPage to increment & decrement the count.

Note: In sequence1 and sequence2, the count should always start from zero.

This is what I done.

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Home Page"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ChangeNotifierProvider<CounterModel>(
              create: (context) => CounterModel(),
              child: RaisedButton(
                child: Text("Sequence1"),
                onPressed: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => IncrementerPage(),
                    ),
                  );
                },
              ),
            ),
            ChangeNotifierProvider<CounterModel>(
              create: (context) => CounterModel(),
              child: RaisedButton(
                child: Text("Sequence2"),
                onPressed: () {
                  Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => OptionsPage(),
                    ),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class OptionsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Consumer<CounterModel>(
          builder: (context, model, child) {
            return Text("Count: ${model.count}");
          },
        ),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            RaisedButton(
              child: Text("Increment"),
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => IncrementerPage(),
                  ),
                );
              },
            ),
            RaisedButton(
              child: Text("Decrement"),
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => DecrementerPage(),
                  ),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

class IncrementerPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Incrementor"),
      ),
      body: Center(
        child: Consumer<CounterModel>(
          builder: (context, model, child) {
            return Text(
              '${model.count}',
              style: const TextStyle(
                fontSize: 32,
                fontWeight: FontWeight.bold,
                color: Colors.black54,
              ),
            );
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () {
          Provider.of<CounterModel>(context, listen: false).increment();
        },
      ),
    );
  }
}

class DecrementerPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Decrementer"),
      ),
      body: Center(
        child: Consumer<CounterModel>(
          builder: (context, model, child) {
            return Text(
              '${model.count}',
              style: const TextStyle(
                fontSize: 32,
                fontWeight: FontWeight.bold,
                color: Colors.black54,
              ),
            );
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.remove),
        onPressed: () {
          Provider.of<CounterModel>(context, listen: false).decrement();
        },
      ),
    );
  }
}

class CounterModel extends ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }

  void decrement() {
    _count--;
    notifyListeners();
  }
}

But I am getting this error:

Could not find the correct Provider<CounterModel> above this Consumer<CounterModel> Widget

By moving ChangeNotifierProvider<CounterModel> outside the MaterialApp fixed the error. But both sequence of pages seems to be using the same counter variable (or model like global). So how to pass different model object per each sequence of pages? or is there any better way to do this?.



Solution 1:[1]

Probably the following code is causing the exception:

floatingActionButton: FloatingActionButton(
    child: Icon(Icons.remove),
    onPressed: () {
        Provider.of<CounterModel>(context, listen: false).decrement();
    },
),

As you can see, the ChangeNotifierProvider for CounterModel is Wrapped around widgets RaisedButton() for sequence 1 and 2 only.

Which are under the body parameter. While the floatingActionButton a colleague parameter for body.

Meaning the Provider.of<CounterModel> can not find the Provider from it's parent widgets.

What you can do is, Move the ChangeNotifierProvider code to cover HomePage and remove every other ChangeNotifierProvider code for CounterModel in the app.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1