Home Start Get started Quick tour of Polymer Install Polymer 2.x Build an element 1. Get set up 2. Add local DOM 3. Data binding & properties 4. React to input 5. Theming with custom properties Build an app 1. Get set up 2. Create a new page 3. Add some elements 4. Deploy Polymer Feature overview About this release What's new in 2.0 Upgrade guide Hybrid elements Release notes Custom elements Custom element concepts Define an element Declare properties Shadow DOM & styling Shadow DOM concepts DOM templating Style shadow DOM Custom CSS properties Events Handle and fire events Gesture events Data system Data system concepts Work with object and array data Observers and computed properties Data binding Helper elements Browser support Overview Polyfills ES6 Tools Tools overview Polymer CLI CLI commands Create an element project Create an application project Document your elements Test your elements Web services polymer.json specification Node support Resources Glossary API Reference API Reference Global settings App Toolbox What's in the box? Using the Toolbox App templates Responsive app layout Routing Localization App storage Service worker Deploy Build for production Serve your app The PRPL pattern Case study Shop News Blog Community What's in the box?
Using the Toolbox
App templates Responsive app layout Routing Localization App storage Service worker
Deploy
Build for production Serve your app The PRPL pattern
Case study
Shop News

For client-side routing, App Toolbox uses the <app-route> element to provide modular routing. Modular routing means that instead of having a central repository for all your application's routes, individual components manage some portion of the route, and delegate the rest to other components.

Why modular routing? For background on <app-route> and modular routing, see Encapsulated routing with elements.

Install the app-route package with Bower:

bower install --save PolymerElements/app-route

Your first task is to decide how your app's routes map to elements. For example, if you have an application with several main views:

View Route
User profile view /profile/:user_id
Message list /messages
Message view /detail/:message_id

You might have a main application element and a separate view component for each tab. The application element manages the top-level route, selects one of the views to display, and delegates the rest of the route to the active view. The app element's template might include markup like this:

<!-- app-location binds to the app's URL -->
<app-location route="{{route}}"></app-location>

<!-- this app-route manages the top-level routes -->
<app-route
    route="{{route}}"
    pattern="/:view"
    data="{{routeData}}"
    tail="{{subroute}}"></app-route>

The <app-location> element is simply a proxy for window.location that provides two-way data binding. A single <app-location> element binds the top-level <app-route> element to the state of the URL bar.

The <app-route> element matches the current route against a pattern (where :view represents a parameter). If the pattern matches, the route is active and any URL parameters are added to the data object. In this case, the path /profile/tina matches the top-level route, setting routeData.view to profile. The remainder of the route (/tina) forms the tail.

Based on the route, the app can use <iron-pages> to select a view to display:

<!-- iron-pages selects the view based on the active route -->
<iron-pages selected="[[routeData.view]]" attr-for-selected="name">
  <my-profile-view name="profile" route="{{subroute}}"></my-profile-view>
  <my-message-list-view name="messages" route="{{subroute}}"></my-message-list-view>
  <my-detail-view name="detail" route="{{subroute}}"></my-detail-view>
</iron-pages>

If the current URL is /profile/tina, the <my-profile-view> element is displayed, with its route set to /tina. This view might embed its own <app-route> to process the route: for example, to load the user's data:

<app-route
    route="{{route}}"
    pattern="/:user_id"
    data="{{routeData}}"></app-route>
<iron-ajax url="{{_profileUrlForUser(routeData.user_id)}}
           on-response="handleResponse" auto>

The route object contains two properties:

  • prefix. The path matched by the previous <app-route> element. For the top-level <app-route> element, prefix is always the empty string.
  • path. The path this route object is matching against.

The tail object is also a route object, representing the route to pass to the next <app-route> in line.

For example, if the current URL is /users/bob/messages and the top-level <app-route> has the pattern `/users/:user':

The route object is:

{
  prefix: '',
  path: '/users/bob/messages'
}

The tail object is:

{
  prefix: '/users/bob',
  path: '/messages'
}

And the routeData object is:

{
  user: 'bob'
}

When using <app-route>, there are two ways to change the current URL.

  • Links. When you click a link, <app-location> intercepts the navigation event and updates its route property. Using links for your primary navigation is a good idea because they help search indexers understand the structure of your application.

  • Updating the route. The route object is read-write, so you can use two-way data binding or this.set to update the route. Both the route and routeData objects can be manipulated this way. For example:

    this.set('route.path', '/search/');

    Or:

    this.set('routeData.user', 'mary');

Previous sections showed data binding to routes and route data, but sometimes you need to run code when the route changes. Using observers, it's simple to react to changes to the route or data:

Route observer example

static get observers() {
  return [
    '_routeChanged(route.*)',
    '_viewChanged(routeData.view)'
  ]
}

_routeChanged(changeRecord) {
  if (changeRecord.path === 'path') {
    console.log('Path changed!');
  }
}
_viewChanged(view) {
  // load data for view
}