I created a Polymer element <bind-view>
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 <app-element>
contains the <bind-view>
element, a placeholder where the view configured for the current route gets added.
Views can be nested. Any view can itself contain a <bind-view>
element. This allows to create hierarchical view composition without much boilerplate.
<!DOCTYPE html>
<link rel='import' href='../../../../packages/polymer/polymer.html'>
<link rel='import' href='../../../../packages/bwu_polymer_routing/bind_view.html'>
<link rel='import' href='user_list.html'>
<link rel='import' href='user_element.html'>
<link rel='import' href='article_list.html'>
<link rel='import' href='article_element.html'>
<polymer-element name='app-element'>
<template>
<bind-view id='app-element'></bind-view>
</template>
<script type='application/dart' src='app_element.dart'></script>
</polymer-element>
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'];
}
}