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...',
),
),
],
),
);