Data transfer between pages with ChangeNotifierProvider in Flutter

Issue

I’m developing an application with Flutter. I split the screen in half. There are buttons on the upper screen. The pages at the bottom of the screen will change as you press those buttons.
I used ChangeNotifierProvider for this working. But it gave the following error. Without opening the admin panel, it gives this error by painting the screen red.

I’ve also looked at the situations that will cause this error, none of them have a problem. I do not understand exactly where the error is.

Can anyone help me to fix codes?

Error Message:

Error: Could not find the correct Provider above this AdminHomePage Widget
This happens because you used a BuildContext that does not include the providerof your choice. There are a few common scenarios:

  • You added a new provider in your main.dart and performed a hot-reload. To fix, perform a hot-restart.
  • The provider you are trying to read is in a different route.
    Providers are "scoped". So if you insert of provider inside a route, then other routes will not be able to access that provider.
  • You used a BuildContext that is an ancestor of the provider you are trying to read.
    Make sure that AdminHomePage is under your MultiProvider/Provider. This usually happens when you are creating a provider and trying to read it immediately.

The codes that make up the image on the screen (relevant lines of code: 3.4.15.71.86.) =

void main() {
  runApp(
    ChangeNotifierProvider<StateAltMenuData>(
      create: (BuildContext context) => StateAltMenuData(),
      child: MaterialApp(
        home: AdminHomePage(),
      ),
    ),
  );
}
 
class AdminHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Function altMenu = Provider.of<StateAltMenuData>(context).altMenuDegistir;
 
    final screenHeight = MediaQuery.of(context).size.height;
    return Scaffold(
      body: Column(
        children: <Widget>[
          Expanded(
            flex: 3,
            child: Stack(
              children: <Widget>[
                OpaqueImage(
                  color: primaryColorOpacity.withOpacity(0.85),
                  imageUrl: "assets/images/kitap_arkaplan.jpg",
                ),
                SafeArea(
                  child: Padding(
                    padding: const EdgeInsets.all(4),
                    child: Column(
                      children: [
                        Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: [
                            Align(
                              alignment: Alignment.centerLeft,
                              child: IconButton(
                                icon: const Icon(Icons.star),
                                color: Colors.white,
                                onPressed: () {
                                  Navigator.pushAndRemoveUntil(
                                      context,
                                      PageTransition(
                                          type: PageTransitionType.fade,
                                          child: UserHomePage()),
                                      (Route<dynamic> route) => false);
                                },
                              ),
                            ),
                            Align(
                              alignment: Alignment.topCenter,
                              child: Text(
                                "Yönetici Sayfası",
                                textAlign: TextAlign.center,
                                style: headingTextStyle,
                              ),
                            ),
                            Align(
                              alignment: Alignment.centerRight,
                              child: IconButton(
                                icon: const Icon(
                                    Icons.supervisor_account_rounded),
                                color: Colors.white,
                                onPressed: () {},
                              ),
                            ),
                          ],
                        ),
                        ControlButtons(),
                      ],
                    ),
                  ),
                ),
              ],
            ),
          ),
          Expanded(
            flex: 5,
            child: SingleChildScrollView(
              child: Container(
                height: screenHeight * (5 / 8),
                padding: const EdgeInsets.only(top: 0),
                color: Colors.white,
                child: altMenu(),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Codes where state information is kept =

class StateAltMenuData with ChangeNotifier {
  int altMenuIndex = 1;
 
  altMenuDegistir(int yeniIndex) {
    altMenuIndex = yeniIndex;
    notifyListeners();
    switch (yeniIndex) {
      case 1:
        return Kutuphane();
        break;
      case 2:
        return KitapAra();
        break;
      case 3:
        return TalebeEkle();
        break;
      case 4:
        return TalebeAra();
        break;
      default:
        return Container(
          child: Center(
            child: Text("Bir şeyler ters gitti."),
          ),
        );
    }
  }
}

Codes for the buttons (related code lines: 4.11.23.39.51.) =

class ControlButtons extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Function yeniIndex = Provider.of<StateAltMenuData>(context).altMenuDegistir;
    return Table(
      children: [
        TableRow(
          children: [
            GestureDetector(
              onTap: () {
                yeniIndex(1);
              },
              child: ControlButtonCard(
                icon: Icon(
                  Icons.add_circle_outline_rounded,
                  color: Colors.blue,
                ),
                text: "Kütüphane",
              ),
            ),
            GestureDetector(
              onTap: () {
                yeniIndex(2);
              },
              child: ControlButtonCard(
                icon: Icon(
                  Icons.search_rounded,
                  color: Colors.blue,
                ),
                text: "Kitap Ara",
              ),
            ),
          ],
        ),
        TableRow(
          children: [
            GestureDetector(
              onTap: () {
                yeniIndex(3);
              },
              child: ControlButtonCard(
                icon: Icon(
                  Icons.person_add,
                  color: Colors.blue,
                ),
                text: "Talebe Ekle",
              ),
            ),
            GestureDetector(
              onTap: () {
                yeniIndex(4);
              },
              child: ControlButtonCard(
                icon: Icon(
                  Icons.person_search,
                  color: Colors.blue,
                ),
                text: "Talebe Ara",
              ),
            ),
          ],
        ),
      ],
    );
  }
}

Solution

I have solved the problem. I could not see the solution somewhere. I’ve been working for 3 or 4 days. Maybe it will help someone, not as hard as I do. I leave the solution here.

1- I noticed that the function I run when switching from the user panel to the admin panel is out of ChangeNotifierProvider. I did it like this:

I wrapped the Stateless Widget named AdminHomePage with ChangeNotifierProvider and returned a new class called AdminPage to the child.

void main () (
  runApp (
    MaterialApp (
      home: AdminHomePage (),
    ),
  );
}

class AdminHomePage extends StatelessWidget {
  @override
  Widget build (BuildContext context) {
    return ChangeNotifierProvider <StateAltMenuData> (
        create: (BuildContext context) => StateAltMenuData (),
        child: AdminPage ());
  }
}

class AdminPage extends StatelessWidget {
  @override
  Widget build (BuildContext context) {
    int altMenuIndex = Provider.of <StateAltMenuData> (context) .altMenuIndex;
    final screenHeight = MediaQuery.of (context) .size.height;
    return Scaffold (
      body: Column (

2- After doing this, another problem arose. The function that will display the image in the 86th line above is asking me for a dynamic value, I am returning it empty. I solved it as follows:

I have assigned a variable named altMenuIndex in AdminPage. The value of this variable calls the altMenuIndex in StateAltMenuData. This is already taken by the values ​​on the buttons.

int altMenuIndex = Provider.of <StateAltMenuData> (context) .altMenuIndex;

3- I changed the inside of StateAltMenuData as follows. I created two different function variables. So I can call different functions in different places.

class StateAltMenuData with ChangeNotifier {
  int altMenuIndex = 1;

  void change altMenuIndex (int newIndex) (
    altMenuIndex = newIndex;
    notifyListeners ();
  }

  Change subMenu (subMenuIndex) (
    switch (subMenuIndex) (
      case 1:
        return Library ();
        break;
      case 2:
        return Search Book ();
        break;
      case 3:
        return Add to Request ();
        break;
      case 4:
        returnCall Request ();
        break;
      default:
        return Container (
          child: Center (
            child: Text ("Something went wrong"),
          ),
        );
    }
  }
}

Answered By – pirekare

Answer Checked By – Terry (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.