I’ve seen a number of different requests for examples of how to use the route package with Polymer. As it so happens, I also needed this functionality for one of my own projects. After getting it working for my use case, I decided to write a little mini sample.
For the impatient of you, you can go right to the source.
The method I use in my sample is just one way of accomplishing the same result. As we go through the code I’ll point out a couple areas where we could take a different approach. My approach will not work for everyone, however with a little trial you may be able to get it to fit your use case.
To begin with, we will start with our custom elements that we will display. In this case I went with
two-element and a special default element called
help-me. The contents are very simple with a header saying element one, element two and some basic help information in each element respectively. Due to an issue with the
noscript attribute, I also included an empty default class for each of the components.
Next we have our
example-app custom element. This will be the container for all of our custom elements and will be essentially the only tag in our main HTML file. First we import the 3 custom element’s we’ve created. Next we add a couple of buttons, each with a on-click event handler which calls the
updatePage method and each with a data field
data-name which contains the page it should load. Finally we add a container div which our content will be loaded into.
ExampleApp class first declares
@published String page = ''; This will be the attribute which indicates which custom element we should have loaded in our container div. As we should all know by know, the
@published annotation makes the variable an attribute on our custom element, as well as making the variable observable. Because of the magic that is Observables, we also have a method with the signature
void pageChanged(oldValue), this method is called any time the page variable changes. With observables, we can automatically bind a method to be called any time the observable variable is changed just by creating a method which has the same name as the variable appended with
Changed and which takes the old value of the variable as an argument. How cool is that!
pageChanged method is where most of the magic happens. First we made a redundant check to make sure that the page variable is not set to the same variable it was before. This is redundant as the observe library should handle that properly for us. Next if the page is blank, we want to remove anything from our container. Finally we need to determine which custom element should be inserted into the container. In this case I used a simple switch to allow for multiple possible values. Either
1 to load the
one-element. Similar for the
two-element. And finally in this case I decided that anything else set for the page should load the
help-me element to display help information. Chances are you’ll want to generate an error or 404 page instead.
Once we determine which element should be loaded, we pass it to the private
_addElement method where we actually create the element and add it to the page. Both this method and the
pageChanged use the new automatic node finding property
$ to query for the div with an id of
container. A little easier than using the old method of
updatePage event handler very simply pulls the
name out of the data field and passes it to the window’s location hash fragment. It does not directly interact with the
page variable or the container itself. Only updates the location. We’ll see why in a second.
Our main HTML file is
routes_example.html, consider this our index page. All our page contains is the import for our example-app tag, the tag itself and its own script. The script is where the routing happens. In
routes_example.dart the first line is our route matcher to use. In this case we have to use the full path as the route package doesn’t easily support relative paths. This also means that we will probably have to change the matcher in the event we deploy the app. We have one group to match in our simple sample, which will be any alpha-numeric characters after the hash in the address. This works out great, since earlier in our
updatePage method only modifies the hash of the current location. Additionally, using the has means we do not require any server side support for http rewrites.
In our main function we just create our router, add a route handler based on our URL and just start listening for connections. The
route_hander function will receive the full path that matches our particular route. From this we want to retrieve the first (and only) matching group from the pattern. We then grab the model associated with our example-app custom tag and pass the matching group from our URL to the
The flow of the program thus is basically as follows:
- Button click.
- Update location hash in the
- Route detects change to location hash and updates the
pagevariable in the ExampleApp class.
- Update of the page variable triggers the
pageChangedhandler which determines correct custom element.
_addElementcreates the custom element and adds it into the content div (after clearing existing children).
While a little circular, this prevents updating the page variable twice with the same value if we did so directly in the updatePage handler. This also allows us to not just use navigational buttons but to also enter the address manually in the address bar (or bookmark a page). It’s certainly not the optimal usage but for our sample it serves its purpose.
There are a number of changes that can be made to extend the sample further such as additional matching groups to our UrlPattern. Additionally its important to keep in mind that a location can only contain one hash (#). Any further hashes should be converted to a forward slash. The Route package is very forgiving on converting between hashes and forward slashes. Hopefully this information can at least help get your started on using route for at least basic capabilities in your projects.