Search code examples
flutterblocflutter-provider

How to access Provided (Provider.of()) value inside showModalBottomSheet?


I have a FloatingActionButton inside a widget tree which has a BlocProvider from flutter_bloc. Something like this:

BlocProvider(
  builder: (context) {
    SomeBloc someBloc = SomeBloc();
    someBloc.dispatch(SomeEvent());

    return someBloc;
  },
  child: Scaffold(
    body: ...
    floatingActionButton: FloatingActionButton(
      onPressed: _openFilterSchedule,
      child: Icon(Icons.filter_list),
    ),
  )
);

Which opens a modal bottom sheet:

void _openFilterSchedule() {
    showModalBottomSheet<void>(
      context: context,
      builder: (BuildContext context) {
        return TheBottomSheet();
      },
    );
  }

I am trying to access SomeBloc using BlocProvider.of<SomeBloc>(context) inside TheBottomSheet but I get the following error:

BlocProvider.of() called with a context that does not contain a Bloc of type SomeBloc.

I have tried to use the solution described in https://stackoverflow.com/a/56533611/2457045 but only works for BottomSheet and not ModalBottomSheet.


Note: This is not restricted to BlocProvider or flutter_bloc. Any Provider from the provider package has the same behaviour.

How can I access BlocProvider.of<SomeBloc>(context) inside the showModalBottomSheet?

In case it's not possible to do that, how to adapt https://stackoverflow.com/a/56533611/2457045 solution to Modal Bottom Sheet?


Solution

  • InheritedWidgets, and therefore Providers, are scoped to the widget tree. They cannot be accessed outside of that tree.

    The thing is, using showDialog and similar functions, the dialog is located in a different widget tree – which may not have access to the desired provider.

    It is therefore necessary to add the desired providers in that new widget tree:

    void myShowDialog() {
      final myModel = Provider.of<MyModel>(context, listen: false);
      showDialog(
        context: context,
        builder: (_) {
          return Provider.value(value: myModel, child: SomeDialog());
        },
      );
    }