ProviderNotFoundException was thrown building ConsumptionDialog because used `BuildContext` that does not include the provider

542

The way provider works is when you do Provider.of<T>(context)(The context must be a descendent of the widget where you injected T) it looks up the tree to find the T that you injected using Provider(create: (_)=> T())(can be ChangeNotifierProvider too doesn't matter). Also routes in the navigator stack aren't a parent of each other they are

-> page1
-> page2

not

-> page1
   -> page2

So this means when you use the Navigator to push a new page, Provider won't be able to find the injected provider you put on page1. And showModal uses Navigator push to open a dialog so basically just like any other route which means your ConfirmationDialog isn't finding the WaterBloc which you probably injected in the page you are opening it from.

One way to solve this is inject WaterBloc above the Navigator, MaterialApp contains the root navigator so inject the provider above Material App.

Another way is when opening the dialog you can do

Future<void> showConsumptionDialog(BuildContext context) {
  return showModal(
    context: context,
    builder: (_) => Provider.value(
      value: context.read<WaterBloc>(), // this context must be a descendent of the widget where you injected WaterBloc
      child: ConsumptionDialog(),
    ),
  );
}

A small tip, I would recommend you to learn Inherited Widgets a bit if you learn them well you can use Provider pretty easily, because Provider is just a wrapper over InheritedWidget

Share:
542
0732sta
Author by

0732sta

Updated on January 02, 2023

Comments

  • 0732sta
    0732sta over 1 year

    I'm a student and I don't learn mobile development at my school. I really appreciate it if anyone could help me. I dunno how to fix the error and I tried countless times.

    Error: Could not find the correct Provider above this Builder Widget. This happens because you used a 'BuildContext' that does not include the provider of your choice.

    The relevant error-causing widget was ConsumptionDialog. 2 files were involved in this error.

    1st File: consumption_dialog.dart

    class ConsumptionDialog extends StatefulWidget {
      @override
      _ConsumptionDialogState createState() => _ConsumptionDialogState();
    }
    
    class _ConsumptionDialogState extends State<ConsumptionDialog> {
      final _form = GlobalKey<FormState>();
      String? _text;
    
      String? _validateText(String? value) {
        if (value == null) {
          return "2000 ml minimun";
        }
    
        final number = int.tryParse(value);
        if (number != null && number >= 2000) {
          return null;
        }
    
        return "2000 ml minimum";
      }
    
      @override
      Widget build(BuildContext context) {
        final bloc = context.watch<WaterBloc>();
        return AlertDialog(
          title: Text(
            "Daily consumption",
            textAlign: TextAlign.center,
            style: TextStyle(fontWeight: FontWeight.bold),
          ),
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
          content: Form(
            key: _form,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(
                  "Change your daily water consumption goal, in milliliters.",
                  textAlign: TextAlign.center,
                ),
                SizedBox(height: 12),
                TextFormField(
                  maxLength: 4,
                  initialValue: bloc.state.recommendedMilliliters.toString(),
                  keyboardType: TextInputType.number,
                  onSaved: (value) => _text = value,
                  validator: _validateText,
                  autovalidateMode: AutovalidateMode.onUserInteraction,
                  decoration: InputDecoration(
                    hintText: "2000 ml",
                    counterText: "",
                  ),
                ),
                SizedBox(height: 24),
                PrimaryButton(
                  onPressed: () {
                    if (_form.currentState?.validate() ?? false) {
                      _form.currentState?.save();
                      FocusScope.of(context).unfocus();
                      context.read<WaterBloc>().setRecommendedMilliliters(
                            int.parse(_text!),
                          );
                      Navigator.of(context).pop();
                    }
                  },
                  title: "Confirm",
                ),
                SizedBox(height: 10),
                SecondaryButton(
                  onPressed: () => Navigator.of(context).pop(),
                  title: "Cancel",
                ),
              ],
            ),
          ),
        );
      }
    }
    

    The error is shown inline:

      Widget build(BuildContext context) {
        final bloc = context.watch<WaterBloc>();
        return AlertDialog(
    

    2nd File: dialog.dart

    import 'package:flutter/material.dart';
    import 'package:animations/animations.dart';
    
    import 'package:stayhydratedpal/widgets/confirmation_dialog.dart';
    import 'package:stayhydratedpal/widgets/consumption_dialog.dart';
    
    Future<bool> showConfirmationDialog(
      BuildContext context, {
      required String title,
      required String content,
    }) async {
      final bool confirmed = await showModal(
            context: context,
            builder: (context) {
              return ConfirmationDialog(
                title: title,
                content: content,
                onConfirm: () => Navigator.of(context).pop(true),
                onCancel: () => Navigator.of(context).pop(false),
              );
            },
          ) ??
          false;
    
      return confirmed;
    }
    
    Future<void> showConsumptionDialog(BuildContext context) {
      return showModal(
        context: context,
        builder: (context) => ConsumptionDialog(),
      );
    }
    

    The error is shown inline:

    Future<void> showConsumptionDialog(BuildContext context) {
      return showModal(
        context: context,
        builder: (context) => ConsumptionDialog(),
      );
    }