There is very good amount of examples but not a single complex one
Now lets say this is my route design
Home->Visit Plans->Visit Plan Rows->Retailer Detail->Sales (on sales, products, basket, calculations etc.)
Now from top to down, meaning on creating sales, i have to update all of them till Visit Plans route.
For example, Updating is visited flag for retailer, or Completed flag for Visit Plan when sales created.
I already implemented an architecture for this with a Bloc for each route and providing previous BLoc on child route but i am not sure is this the correct way to handle it. For now, its working perfectly but still i want some opinion.
This is my router class with Blocs from top to sales screens:
class Router {
final _visitPlansBloc = VisitPlansBloc(
visitPlansRepository: DBVisitPlansRepository(),
);
final _visitPlanRowsBloc = VisitPlanRowsBloc(
visitPlanRowsRepository: DBVisitPlanRowsRepository(),
);
final _retailerBloc = RetailerBloc(
retailerRepository: DBRetailerRepository(),
);
Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case RouteNames.startRoute:
return MaterialPageRoute(builder: (_) => SplashPage());
case RouteNames.loginRoute:
return MaterialPageRoute(builder: (_) => LoginPage());
case RouteNames.homeRoute:
return MaterialPageRoute(
builder: (_) => MultiBlocProvider(providers: <BlocProvider>[
BlocProvider<SyncBloc>(
create: (context) => SyncBloc(syncService: SyncService(), userBloc: BlocProvider.of<UserBloc>(context)),
)
], child: HomePage()));
case RouteNames.visitPlanRoute:
return MaterialPageRoute(builder: (_) => BlocProvider.value(value: _visitPlansBloc, child: VisitPlanPage()));
case RouteNames.visitPlanRowsRoute:
var data = settings.arguments as VisitPlanModel;
return MaterialPageRoute(builder: (_) => BlocProvider.value(value: _visitPlansBloc, child: BlocProvider.value(value: _visitPlanRowsBloc, child: VisitPlanRowPage(visitPlanModel: data))));
case RouteNames.visitPlanRowDetailRoute:
var data = settings.arguments as VisitPlanRowModel;
return MaterialPageRoute(
builder: (_) => MultiBlocProvider(providers: <BlocProvider>[
BlocProvider<VisitPlansBloc>.value(value: _visitPlansBloc),
BlocProvider<VisitPlanRowsBloc>.value(value: _visitPlanRowsBloc),
BlocProvider<RetailerBloc>.value(value: _retailerBloc)
], child: RetailerDetailPage(visitPlanRowModel: data)));
case RouteNames.salesConfirmationRoute:
var data = settings.arguments as VisitPlanRowModel;
return MaterialPageRoute(
builder: (_) => MultiBlocProvider(providers: <BlocProvider>[
BlocProvider<VisitPlansBloc>.value(value: _visitPlansBloc),
BlocProvider<VisitPlanRowsBloc>.value(value: _visitPlanRowsBloc),
BlocProvider<RetailerBloc>.value(value: _retailerBloc),
BlocProvider<OrderMainBloc>(
create: (context) => OrderMainBloc(
orderMainRepository: DBOrderMainRepository(),
)..add(LoadOrderMain(data.vphId)),
),
BlocProvider<OrderProductsBloc>(
create: (context) => OrderProductsBloc(orderMainBloc: BlocProvider.of<OrderMainBloc>(context), productRepository: DBProductRepository(), visitPlanId: data.vphId),
),
BlocProvider<OrderProductsFilterBloc>(
create: (context) => OrderProductsFilterBloc(orderProductsBloc: BlocProvider.of<OrderProductsBloc>(context)),
)
], child: SalesConfirmationPage(visitPlanRowModel: data)));
default:
return MaterialPageRoute(
builder: (_) => Scaffold(
body: Center(child: Text('No route defined for ${settings.name}')),
));
}
}
void dispose() {
_visitPlansBloc.close();
_visitPlanRowsBloc.close();
_retailerBloc.close();
}
}
Hi @callawey 馃憢
Thanks for opening an issue!
The approach you've provided seems totally reasonable. One suggestion for potentially improving/simplifying things would be to use nested Navigators for each "feature" or "flow" and that way you can provide the blocs required above the Navigator and not need to pass the blocs through each route push via BlocProvider.value.
For example:
BlocProvider(
create: (context) => FeatureABloc(),
child: Navigator(onGenerateRoute: (_) => FeatureAPage.route()),
);
class FeatureAPage extends StatelessWidget {
static Route route() {
return MaterialPageRoute(builder: (_) => FeatureAPage());
}
@override
Widget build(BuildContext context) { ... }
}
With this approach the FeatureABloc instance is available even across multiple MaterialPageRoutes within FeatureAPage. Hope that helps 馃憤
Closing for now but feel free to comment with additional questions and I'm happy to continue the conversation 馃憤
Most helpful comment
Hi @callawey 馃憢
Thanks for opening an issue!
The approach you've provided seems totally reasonable. One suggestion for potentially improving/simplifying things would be to use nested
Navigatorsfor each "feature" or "flow" and that way you can provide the blocs required above theNavigatorand not need to pass the blocs through each route push viaBlocProvider.value.For example:
With this approach the
FeatureABlocinstance is available even across multiple MaterialPageRoutes withinFeatureAPage. Hope that helps 馃憤