fnx_router
Declarative hierarchical router for Polymer Dart 1.0. Use it like this:
<fnx-router>
<a href="#/amazing/stuff">show me amazing stuff</a>
<a href="#/amazing/features">show me amazing features</a>
<fnx-router route="amazing">
<fnx-router route="stuff">
<h1>wow!</h1>
</fnx-router>
<fnx-router route="features">
<h1>no way!</h1>
</fnx-router>
...
Comes in with handy Polymer @bahavior
which you can use to make any of your elements routing capable.
Note: Work in progress, I'll continue to develop this package as I use it in our Polymer projects.
Routing
The purpose of this package is to allow you to show/hide your elements depending on window.location.hash
value. Every element with FnxRouterBehavior
has route
attribute and becomes subject of routing.
<fnx-router route='user'>
<my-cool-element route='edit'>
...
Elements create a tree hierarchy of routing nodes (subtree of DOM, if you want). Their absolute route depends on route of their parents (and recursively up to the root element).
<fnx-router> <!-- this is a routing root and it has no
"route" attribute , it will be visible always -->
<fnx-router route="amazing"> <!-- visible on #/amazing -->
<fnx-router route="stuff"> <!-- visible on #/amazing/stuff -->
<fnx-router route="vol1"> <!-- visible on #/amazing/stuff/vol1 -->
Level separator /
is a constant provided by fnx_router.
Navigation
Your user can navigate through your app by simply changing location anchor:
<a href="#/amazing/stuff">show me amazing stuff</a>
<a href="#/amazing/features">show me amazing features</a>
However - this requires you to know the absolute path (absolute route) to the element, which is not very practical - hierarchical routing then loses it's purpose. There are several other ways how to navigate.
<fnx-router>
<a href="#" data-router="#/amazing">open amazing menu</a>
<fnx-router route="amazing">
<a href="#" data-router="./stuff">stuff</a>
<a href="#" data-router="./features">features</a>
<a href="#" data-router="../regular">hide amazing, show regular</a>
<fnx-router route="stuff">
<h1>WOW!</h1>
</fnx-router>
<fnx-router route="features">
<h1>NO WAY!</h1>
</fnx-router>
</fnx-router>
<fnx-router route="regular">
This is pretty regular. Go see
<a href="#" data-router="../amazing">something amazing</a>.
</fnx-router>
All routing nodes listen for tap
event (@Listen("tap")
). If the event's target contains data-router
attribute, tap event is canceled and processed by router (actual href
or other default action is ignored).
Possible values of data-router
are:
#/something
- absolute path to required element./something
- relative path to this element's child../something
- relative path to this element's siblink (only single '../' is supported for now, you cannot double-dot your path all the way up like '../../')
Your data-router
value must start with either #/
, ./
or ../
.
<a href="#" data-router="./baby-boy">pictures of my boy</a>
<a href="#" data-router="./baby-girl">pictures of my girl</a>
<a href="#" data-router="../my-dumb-brother">pictures of my brother</a>
You can also change the route programmatically, but more about this later.
fnx-router element
fnx_router package contains <fnx-router>
element. It's a
simple display: block;
element. You can use it instead of
your regular <div>
.
Styling
FnxRouterBehavior
toggles two boolean attributes on your element during routing:
router-visible
router-invisible
Use those attributes to hide your elements however you want:
<style>
fnx-router[router-invisible] {
display: none;
}
.show-ghosts fnx-router[router-invisible] {
opacity: 0.2;
}
</style>
Note: It's discouraged to remove elements from DOM tree, see polymer-dart wiki, that's one of the reasons we leave handling invisible elements up to you.
To prevent FUOC, add router-not-initialized
to body element and style it:
<style>
body[router-not-initialized] {
opacity: 0;
}
</style>
After successful initialization, fnx_router exchanges this attribute for router-initialized
.
Routing parameters
It would be nice to have routes like this: /user/1234/edit
, but in current
state of Polymer it would be difficult to create such link. Polymer doesn't
support expressions at this moment, so you cannot write
href="/user/{{user.id}}/edit"
.
Because of this, your routes should be "hardwired constants" and everything what changes, should be provided via parameters.
<a href="#/my/hardwired/route;3.1415;another-parameter">go for PI</a>
You still cannot render href="#/my/hardwired/route;{{currentValueOfPI}};another-parameter"
, but you can use additional data-router
attributes:
<a href="#"
data-router="#/my/hardwired/route"
data-router-param1="{{currentValueOfPI}}"
data-router-param2="another-parameter"
>go for PI</a>
Note: At this point routing parameters are simply a List<String>
.
Using router in your elements
fnx-router
element is really just a smarter div. You will probably need to fetch data from API
whenever your element becomes visible etc. Good news - thanks to Polymer behaviors,
it's really easy.
Enhance your element with FnxRouterBehavior
like this:
In your template:
<dom-module id="my-smart-rest-element" attributes="route"><!-- new attribute -->
In your class:
class MySmartRestElement extends PolymerElement with FnxRouterBehavior {
...
And add a callback for visibility changes:
void routeChanged(bool visible, List<String> params) {
if (visible) { foo(); } else { bar(); }
}
For example, fnx-router
element looks like this:
@PolymerRegister("fnx-router")
class FnxRouter extends PolymerElement with FnxRouterBehavior {
FnxRouter.created() : super.created();
void routeChanged(bool visible, List<String> params) {
if (visible) {
toggleAttribute("router-visible", true);
} else {
toggleAttribute("router-visible", false);
}
}
It cannot be easier! routeChanged
callback will be invoked each time when:
- your element is invisible and should become visible
- your element is visible and should become invisible
- your element is visible and should stay visible, but params changed (see Routing parameters above)
API
With FnxRouterBehavior
your element has access to:
// current state of visibility
@property(notify: true)
bool routerVisible = false;
// last routing parameters
@property(notify: true)
List<String> routerParams = [];
// absolute route to parent element (/amazing)
@property
String absoluteParentRoute = null;
// absolute route to this element (/amazing/stuff)
@property
String absoluteRoute = null;
Notes, details and TODOs
Routing rules for element are evaluated in attached()
Polymer lifecycle method and cannot be changed later.
fnx-router works only with shady DOM.
Contact
Feel free to contact me at <user-element>tomucha</user-element><host-element separator="@">gmail.com</host-element>
,
or fill-in a bugreport on Github issue tracking.
Libraries
- fnx_router.behavior
-
Routing behavior for Polymer elements. …
- fnx_router.element
-
Simple element with FnxRouterBehavior.