Home > Net >  Error: Could not find the correct Provider<RecipeProvider> above this AddRecipe Widget
Error: Could not find the correct Provider<RecipeProvider> above this AddRecipe Widget

Time:01-09

`I want to access the provider in the AddRecipe page in order to save a new recipe and notify the listeners, in my case the list.builder in UserRecipes to rebuild.

Sorry for the big amount of code, I added everything that I thought may be useful. I just can't figure it out, have been trying for hours. This is the error that I get:

ProviderNotFoundException (Error: Could not find the correct Provider<RecipeProvider> above this AddRecipe Widget

These are the files:

Wrapper.dart:

class Wrapper extends StatelessWidget {
  const Wrapper({super.key});

  @override
  Widget build(BuildContext context) {
    
    final user = Provider.of<User?>(context);

    if (user == null) {
      return const AuthPage();
    } else {
      return MultiProvider(
        providers: [
          ChangeNotifierProvider(create: (_) => RecipeProvider(uid: user.uid))
        ],
        child: const HomePage()
      );
    }
  }
}

Home.dart:

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {

  final AuthService _auth = AuthService();

  // The 4 main application screens
  static const List<Destination> allDestinations = <Destination>[
    Destination(0, 'Home', Icons.home, Colors.teal),
    Destination(1, 'Meals', Icons.dinner_dining, Colors.orange),
    Destination(2, 'Recipes', Icons.restaurant_menu_sharp, Colors.amber),
    Destination(3, 'Profile', Icons.person, Colors.blue),
  ];

  int currentPageIndex = 0;

  final screens = [
    Center(child: Text('Home'),),
    Center(child: Text('Meals'),),
    RecipesPage(),
    Center(child: Text('My profile'),),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: CustomAppBar(title: allDestinations[currentPageIndex].title, backButton: false, signOutButton: true),
      bottomNavigationBar: NavigationBar(
        onDestinationSelected: (int index) {
          setState(() {
            currentPageIndex = index;
          });
        },
        selectedIndex: currentPageIndex,
        destinations: allDestinations.map((Destination destination) {
          return NavigationDestination(
            icon: Icon(destination.icon, color: destination.color), 
            label: destination.title
          );
        }).toList(),
      ),
      body: screens[currentPageIndex]
    );
  }
}

class Destination {
  const Destination(this.index, this.title, this.icon, this.color);
  final int index;
  final String title;
  final IconData icon;
  final MaterialColor color;
}

Recipes.dart:

const List<Widget> recipes = <Widget>[
  Text('My recipes'),
  Text('Other recipes')
];

class RecipesPage extends StatefulWidget {
  const RecipesPage({super.key});

  @override
  State<RecipesPage> createState() => _RecipesPageState();
}

class _RecipesPageState extends State<RecipesPage> {

  final List<bool> _selectedRecipes = <bool>[true, false];

  final _searchContoller = TextEditingController();

  @override
  void dispose() {
    _searchContoller.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {

    var provider = context.watch<RecipeProvider>();

    return Scaffold(
      body: SafeArea(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: [
              SizedBox(height: 20),
              
              ToggleButtons(
                direction: Axis.horizontal,
                onPressed: (int index) {
                  setState(() {
                    for (int i = 0; i < _selectedRecipes.length; i  ) {
                      _selectedRecipes[i] = i == index;
                    }
                  });
                },
                borderRadius: const BorderRadius.all(Radius.circular(12)),
                selectedBorderColor: Colors.blue[700],
                selectedColor: Colors.white,
                fillColor: Colors.blue[200],
                color: Colors.blue[400],
                constraints: const BoxConstraints(
                  minHeight: 40.0,
                  minWidth: 165.0,
                ),
                isSelected: _selectedRecipes,
                children: recipes
              ),

              SizedBox(height: 10),
          
              // Search textfield
              Padding(
                padding: const EdgeInsets.symmetric(horizontal: 30.0),
                child: TextField(
                  controller: _searchContoller,
                  decoration: InputDecoration(
                    enabledBorder: OutlineInputBorder(
                      borderSide: BorderSide(color: Colors.white),
                      borderRadius: BorderRadius.circular(12),
                    ),
                    focusedBorder: OutlineInputBorder(
                      borderSide: BorderSide(color: Colors.blue),
                      borderRadius: BorderRadius.circular(12),
                    ),
                    hintText: 'Search',
                    fillColor: Colors.grey[250],
                    filled: true
                  ),
                ),
              ),
              SizedBox(height: 20),

              Expanded(
                child: _getRecipePage(),
              ),

            ],
          )
        ),
      ),
      floatingActionButton: Consumer<RecipeProvider>(
        builder: (context, value, child) {
          return _getFAB();
        },
      )
    );
  }

  Widget _getFAB() {
    if (_selectedRecipes[1]) {
      return Container();
    } else {
      return FloatingActionButton(
        child: Icon(Icons.add, size: 35),
        onPressed: () => { 
          Navigator.of(context).push(
            MaterialPageRoute(
              builder: (_) => AddRecipe()
            )
          ),
        },
      );
    }
  }

  Widget _getRecipePage() {
    if (_selectedRecipes[0]) {
      return UserRecipesWidget(search: _searchContoller.text.trim());
    } else {
      return OtherRecipesWidget();
    }
  }
}

User_recipes.dart:

class UserRecipesWidget extends StatefulWidget {
  UserRecipesWidget({super.key, required this.search});

  String search;

  @override
  State<UserRecipesWidget> createState() => _UserRecipesWidgetState();
}

class _UserRecipesWidgetState extends State<UserRecipesWidget> {

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {

    var provider = context.watch<RecipeProvider>();

    return FutureBuilder(
      future: provider.getUserRecipesFuture,
      builder: (BuildContext ctx, AsyncSnapshot asyncSnapshot) {
        if (asyncSnapshot.connectionState == ConnectionState.done) {
          if (asyncSnapshot.hasError) {
            return const Center(child: Text('Could not retreive recipes!'));
          }
          return ListView.builder(
            itemCount: provider.recipes.length,
            itemBuilder: (BuildContext ctx, int index) {
              return GestureDetector(
                onTap: () => { 
                  Navigator.of(context).push(
                    MaterialPageRoute(
                      builder: (context) => RecipePage(recipe: provider.recipes[index])
                    )
                  ),
                },
                child: RecipeCard(recipe: provider.recipes[index]),
              );
            }
          );
        } else {
            return Center(child: CircularProgressIndicator());
        }
      }
    );
  }
}

RecipeProvider:

class RecipeProvider extends ChangeNotifier {

  late RecipeService _recipeService;
  List<RecipeModel> recipes = [];
  late Future getUserRecipesFuture;
  final String uid;

  RecipeProvider({ required this.uid }) {
    _recipeService = RecipeService(uid: uid);
    getUserRecipesFuture = _getUserRecipesFuture();
    
  }

  Future _getUserRecipesFuture() async {
    recipes = await _recipeService.getUserRecipes();
    addDummyRecipe();
  }

  addDummyRecipe() {
    recipes.add(RecipeModel(uid: "test", userId: "test", recipeName: "Pork"));
    recipes.add(RecipeModel(uid: "test1", userId: "test1", recipeName: "Pizza"));
    recipes.add(RecipeModel(uid: "test2", userId: "test2", recipeName: "Burger"));
    notifyListeners();
  }
}

And the main one that gives the error, add_recipe.dart:

class AddRecipe extends StatefulWidget {
  const AddRecipe({super.key});

  @override
  State<AddRecipe> createState() => _AddRecipeState();
}

class _AddRecipeState extends State<AddRecipe> {

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    
    return Scaffold(
      appBar: CustomAppBar(title: 'Add recipe', backButton: true),
      body: SafeArea(
        child: Center(
          child: Column(
            children: [
              Text('Add recipe'),

              SizedBox(height: 50),

              // Add recipe button
              Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 30.0),
                  child: GestureDetector(
                    onTap: () async {
                      context.read<RecipeProvider>().addDummyRecipe();
                    },
                    child: Container(
                      padding: EdgeInsets.all(16),
                      decoration: BoxDecoration(
                        color: Colors.green,
                        borderRadius: BorderRadius.circular(12),
                      ),
                      child: Center(
                        child: Text(
                          'Save recipe',
                          style: TextStyle(
                            color: Colors.white,
                            fontWeight: FontWeight.bold,
                            fontSize: 20,
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
            ]
          )
        )
      ),
    );
  }
}

`

CodePudding user response:

the exception happens because you provided the RecipeProvider only for the HomePage(). means when you push a new route, it doesn't have that the RecipeProvider instance.

if you can't provide the RecipeProvider Golobally because it needs the uid, then you must provide it each time you push a new route

change your RecipePage Navigator to this

Navigator.of(context).push(
  MaterialPageRoute(
  builder: (_) => ChangeNotifierProvider.value(
    value: context.read<RecipeProvider>(),
    child: RecipePage(recipe: provider.recipes[index]),
    ),
  ),
),

and your AddRecipe

Navigator.of(context).push(
  MaterialPageRoute(
  builder: (_) => ChangeNotifierProvider.value(
    value: context.read<RecipeProvider>(),
    child: AddRecipe(),
    ),
  ),
),
  • Related