'Flutter - Cant find bloc in the parent tree when using showDialog

Im using Flutter and flutter_bloc for a small app, and i used MultiBlocProvider to use multiple BlocProviders that i need in the main home page, and under the home page, there is a MainWidget, which can access the given Bloc easily by: BlocProvider.of<OldBloc>(context) The MainWidget calls NewWidget as a dialog by: showDialog(context: context, builder: (context) => NewWidget()) The problem is, i cannot access OldBloc from NewWidget(), so i assumed that MainWidget isnt passing its context to NewWidget when using showDialog ?

HomeScreen.dart

import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: MultiBlocProvider(
      providers: [
        BlocProvider(
          create: (context) => OldBloc()..add(Initialize()),
        ),
        BlocProvider(
          create: (context) => OtherBloc()..add(Initialize()),
        ),
      ],
      child: Stack(
        children: [
          MainWidget(),
          MenuWidget(),
        ],
      ),
    ));
  }
}

MainWidget.dart

import 'package:flutter/material.dart';

class MainWidget extends StatelessWidget {
  const MainWidget({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return TextField(onTap: () => showDialog(context: context, builder: (context) => NewWidget()));
  }
}

NewWidget.dart

import 'package:flutter/material.dart';

class NewWidget extends StatelessWidget {
  const NewWidget({Key key}) : super(key: key);

  @override
  Widget build(context) {
    return Text(BlocProvider.of<OldBloc>(context).name); // <------- THIS GIVES AN ERROR THAT IT CANT FIND A BLOC OF THE TYPE OldBloc
  }
}


Solution 1:[1]

You can simply use this (suggested by Flex Angelov):

showDialog(
  context: superContext,
  builder: (_) {
    return  BlocProvider.value(
      value: superContext.read<MyBloc>(),
      child: const MyDialogWidget(),
    );
  },
);

and make sure superContext has access to you BLoC.

Solution 2:[2]

I solved this problem.

I use cubit instead of bloc but it doesn't matter.

ShowDialog doesn't pass parent context. So you should create a new cubit and pass your parent cubit and state in arguments for a new cubit. I called main cubit FooCubit, new cubit FooCubitWrapper and DialogWidget is child widget that needs some BLOC logic in showDialog.


    var fooCubit = context.read<FooCubit>(); // your parrent cubit and state
    return BlocBuilder<FooCubit , FooState>(
        builder: (_, state) {
.
.///some logic///
.
          showDialog(
            context: context,
            builder: (_) => // here you have to create new cubit 
                BlocProvider( // because there is no access to parent cubit
                  create: (_) => FooCubitWrapper(cubit, state),
                  child: DialogWidget(),
                ),
          );

This is FooCubitWrapper. For example, we need the boo method from the parent cubit. So we need to create here boo method and inside we need to reference to parent boo method and emit parent state.

class FooCubitWrapper extends Cubit<FooState> {
  FooCubit fooCubit;

  FooCubitWrapper(this.fooCubit, FooState initialState) : super(initialState);

  boo() {
    fooCubit.boo();

    emit(fooCubit.state);
  }
}

And finally, in your DialogWidget, you do all like usual

    var cubit = context.read<TagsCubitWrapper>();
    return BlocBuilder<TagsCubitWrapper, TagsState>(
        builder: (context, state) {

// work with methods and fields as usual
    cubit.boo();
    if !(state.someField) {}

});

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tokenizer
Solution 2 Egor Polyakov