I am going to build complex application having many different views. Imagine for example eshop solution. There can be a lot of different views:
I created a Polymer element that creates and adds a view element depending on the current route. The element works with the route_hierarchical package.
See BWU Polymer Routing on GitHub for more details.
A route configuration looks like
library bwu_polymer_routing_example.route_initializer;
import 'package:route_hierarchical/client.dart' as rt;
import 'package:bwu_polymer_routing/module.dart';
class RouteInitializer implements Function {
void call(rt.Router router, RouteViewFactory views) {
views.configure({
'usersList': routeCfg(
path: '/users',
view: 'user-list',
defaultRoute: true,
dontLeaveOnParamChanges: true,
enter: (route) => router.go('usersList', {})),
'user': routeCfg(
path: '/user/:userId',
view: 'user-element',
dontLeaveOnParamChanges: true,
mount: {
'articleList': routeCfg(
path: '/articles',
view: 'article-list',
defaultRoute: true,
dontLeaveOnParamChanges: true,
mount: {
'article': routeCfg(
path: '/article/:articleId',
view: 'article-element',
bindParameters: ['articleId', 'userId'],
dontLeaveOnParamChanges: true,
mount: {
'view': routeCfg(
path: '/view',
defaultRoute: true,
dontLeaveOnParamChanges: true),
'edit': routeCfg(
path: '/edit',
dontLeaveOnParamChanges: true)
})
})
})
});
}
}
the contains the element, a placeholder where the view configured for the current route gets added.
Views can be nested. Any view can itself contain a element. This allows to create hierarchical view composition without much boilerplate.
The app_element.dart file contains the router initialization code
class AppModule extends Module {
AppModule() : super() {
install(new RoutingModule(usePushState: true));
bindByKey(ROUTE_INITIALIZER_FN_KEY, toValue: new RouteInitializer());
}
}
@CustomTag('app-element')
class AppElement extends PolymerElement with DiContext {
AppElement.created() : super.created();
@override
void attached() {
super.attached();
initDiContext(this, new ModuleInjector([new AppModule()]));
}
}
The package also contains some helper mixins to add dependency injection (DI) functionality to Polymer elements like the DiContext mixin used here.
Constructor injection can't be used with Polymer but events are a good substitute.
The DiConsumer mixin allows to request an instance from DI with this simple code
@CustomTag('article-list')
class ArticleList extends PolymerElement with DiConsumer {
@observable String userId;
@override
void attached() {
super.attached();
// The two lines below show how to request instances from DI
// but they are redundant here because
// route parameters are assigned to attributes of the view automatically
// when the view is created or when the values change
var di = inject(this, [RouteProvider /* add more types here as needed */]);
userId = (di[RouteProvider] as RouteProvider).parameters['userId'];
}
}