Home > Software engineering >  Send the provider in the navigator in flutter
Send the provider in the navigator in flutter

Time:10-28

I am creating an app about shopping lists in flutter and firestore. I am trying to use the bloc pattern now, and when I press a button I want to navigate to a different screen to create a new list, in that screen if I press another button I want call the bloc and the business logic to create a new shopping list and then return to the screen with all the shopping lists of an user.

This is the main where I call the MultiBlocProvider. Right now I have blocProviders one for authentication and other for the shopping lists.

Widget build(BuildContext context) {
FirebaseFunctions functions = FirebaseFunctions.instance;

return MaterialApp(
  title: 'Flutter Demo',
  theme: ThemeData(primarySwatch: Colors.blue),
  debugShowCheckedModeBanner: false,
  home: MultiBlocProvider(
    providers: [
     BlocProvider(
        create: (context) => AuthBloc(FirebaseAuthProvider())),
     BlocProvider(
        create: (context) => ShoppingBloc(FirebaseCloudStorage()),

     )],
    child: const HomePage(),
    ),
  routes: {
    createOrUpdateNoteRoute: (context) => const CreateUpdateNoteView(),
    createOrUpdateShoppingCartListRoute: (context) => const CreateUpdateShoppingCartListView(),
  },
);

This is the button that when I press I want to navigate to a different screen:

IconButton(
          onPressed: () {

            Navigator.push(context,
                MaterialPageRoute(
                    builder: (context) =>
                  BlocProvider<ShoppingBloc>.value(
                    value: context.read<ShoppingBloc>(),
                    child: const CreateUpdateShoppingCartListView(),
                  )
                ),
            );
          },
          icon: const Icon(Icons.add),
        ),

This is the view where I call the bloc:

    @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('New shopping cart list'),
          actions: [
            IconButton(
              onPressed: () {
                final text = _textController.text;
                final ownerUserId = currentUser.id;
                context.read<ShoppingBloc>()
                    .add(ShoppingCreateNewShoppingCartEvent(ownerUserId, 'creating a new list'));
              },
              icon: const Icon(Icons.add),
            ),                 
          ],
        ),
        body: Column(children: [
          TextField(
          controller: _textController,
          keyboardType: TextInputType.multiline,
          maxLines: null,
          textInputAction: TextInputAction.go,
          decoration: const InputDecoration(
            hintText: 'Start typing you shopping cart name...',
          ),
          ),
        ],
        ),
      );

This is the bloc:

class ShoppingBloc extends Bloc<ShoppingEvent, ShoppingState> {

ShoppingBloc(FirebaseCloudStorage provider) : super(ShoppingInitial()) {

on<ShoppingCreateNewShoppingCartEvent>((event, emit) async{
  final ownerUserId = event.ownerUserId;
  final name = event.name;

  try {
    provider.createNewShoppingCartList(ownerUserId: ownerUserId, name: name);
    emit(const StateCreateShoppingCart());
  } catch (e){
    print('There was an error in createNewShoppingCartEvent in bloc');
  }
 });
 }

}

The event:

class ShoppingCreateNewShoppingCartEvent extends ShoppingEvent{
 final String ownerUserId;
 final String name;

const ShoppingCreateNewShoppingCartEvent(this.ownerUserId, this.name);
}

And this is the state:

class StateCreateShoppingCart extends ShoppingState {
  const StateCreateShoppingCart();
}

I am getting the error Could not find the correct Provider<ShoppingBloc> above this Builder Widget. I tried multiple solution proposed but none worked. I think that the provider in the shoppingCartView is different that the provider in the CreateUpdateShoppingCartListView so I want to pass this provider in the navigator or is there a better solution?

Thanks in advance.

CodePudding user response:

You already provided ShoppingBloc inside MaterialApp but also try to provide a new bloc inside here :

BlocProvider<ShoppingBloc>.value(
value: context.read<ShoppingBloc>(),
child: const CreateUpdateShoppingCartListView(),
)

...that's bad...

try this.. add named routes correctly and MOVE MultiBlocProvider out from MaterialApp

Widget build(BuildContext context) {
FirebaseFunctions functions = FirebaseFunctions.instance;

return MultiBlocProvider(
    providers: [
     BlocProvider(
        create: (context) => AuthBloc(FirebaseAuthProvider())),
     BlocProvider(
        create: (context) => ShoppingBloc(FirebaseCloudStorage()),

     ),
    ], 
  child: MaterialApp(
     title: 'Flutter Demo',
     theme: ThemeData(primarySwatch: Colors.blue),
     debugShowCheckedModeBanner: false,
     home: const HomePage(),
     routes: {
       "/createOrUpdateNote": (context) => const CreateUpdateNoteView(),
       "/shopingCartListRoute": (context) => const CreateUpdateShoppingCartListView(),
     },
  ),
);

then you can navigate like this

IconButton(
          onPressed: () {
            Navigator.pushNamed(context, '/shopingCartListRoute');
          },
          icon: const Icon(Icons.add),
        )

and then use your provided bloc (your provided example seems ok)

  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('New shopping cart list'),
          actions: [
            IconButton(
              onPressed: () {
                final text = _textController.text;
                final ownerUserId = currentUser.id;
                context.read<ShoppingBloc>()
                    .add(ShoppingCreateNewShoppingCartEvent(ownerUserId, 'creating a new list'));
              },
              icon: const Icon(Icons.add),
            ),                 
          ],
        ),
        body: Column(children: [
          TextField(
          controller: _textController,
          keyboardType: TextInputType.multiline,
          maxLines: null,
          textInputAction: TextInputAction.go,
          decoration: const InputDecoration(
            hintText: 'Start typing you shopping cart name...',
          ),
          ),
        ],
        ),
      );
  • Related