1

I have a parent ChangeNotifier ParentProvider, and 2 other providers extend the ParentProvider;

ChildProviderA, ChildProviderB.

I have a route which is called MyScreen

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

    if(ModalRoute.of(context).settings.arguments != null){
      return ChangeNotifierProvider(
        create: (context) => ChildProviderA(),
        child: _Screen()
      );
    }
    return ChangeNotifierProvider(
      create: (context) => ChildProviderB(),
      child: _Screen()
    );
  }
}

depending on the arguments I want to use a provider, and in either case, I want to call a function called initData() in the ParentProvider from the _Screen widget.

@override
  Widget build(BuildContext context) {
...
    Provider.of<ParentProvider>(context, listen: false).initData();
...
}

This gives me an error

Error: Could not find the correct Provider<ParentProvider> above this _Screen Widget

If I used Provider.of<ChildProviderA>(context, listen: false).initData();

or Provider.of<ChildProviderB>(context, listen: false).initData(); It works, but I want in either child Provider used, to be able to call initData.

How can this be done ?

Ismaeel Sherif
  • 555
  • 7
  • 15

2 Answers2

1

Provider.of looks for provider with exactly given type. It doesn't include child types.

If the child screen needs to access some different data having same format, you can use the same provider in both cases passing it different data through constructor:

class MyScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    if (condition) {
      return ChangeNotifierProvider(
        create: (context) => ParentProvider(data1),
        child: _Screen(),
      );
    }
    return ChangeNotifierProvider(
      create: (context) => ParentProvider(data2),
      child: _Screen(),
    );
  }
}

If you really have two different ChangeNotifier implementations sharing same interface, you can provide and access them using parent type:

class MyScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    if (condition) {
      return ChangeNotifierProvider<ParentProvider>(
        create: (context) => ChildProviderA(),
        child: _Screen(),
      );
    }
    return ChangeNotifierProvider<ParentProvider>(
      create: (context) => ChildProviderB(),
      child: _Screen(),
    );
  }
}
Pavel
  • 5,374
  • 4
  • 30
  • 55
  • The second example works. It still needed to declare an empty method in the ParentProvider to be able to run it from ChildA, but anyway it saved a lot of code – Ismaeel Sherif Jul 31 '21 at 18:04
  • 1
    To avoid empty methods in parent change notifier, you can make the parent class abstract and declare abstract method – Pavel Jul 31 '21 at 18:05
0

When you define your children providers, use extends. Also all providers must above the children and in the same route they are listening to. You can try adding extends ParentProvider when defining your children classes. i.e

class ChildA  extends ParentProvider {

//here you have access to methods in parent.
you can add a method here that triggers something form the parent.

void childMethod ()=> methodFromParentLikeInitData();

}
Huthaifa Muayyad
  • 11,321
  • 3
  • 17
  • 49