Jiew Meng
Jiew Meng

Reputation: 88197

Polymer route/iron-pages not working?

I am just trying out Polymer 1.0. I find that app-route/iron-pages is not working. Navigating between routes does not appear to show the correct view. Not sure which part went wrong:

In the main file:

<app-drawer-layout>
  <app-location route="{{route}}"></app-location>

  <app-route
    route="{{route}}"
    pattern="/:view"
    data="{{routeData}}"
    tail="{{subroute}}"></app-route>

  <app-drawer>
    <main-drawer></main-drawer>
  </app-drawer>

  <app-header-layout>
    <app-header>
      <paper-toolbar>
        <paper-icon-button icon="menu" drawer-toggle></paper-icon-button>
        <div class="title">
          Expenses App
        </div>
      </paper-toolbar>

      <iron-pages selected="[[view]]">
        <expenses-dashboard name="dashboard" route="{{subroute}}"></expenses-dashboard>
        <expenses-settings name="settings" route="{{subroute}}"></expenses-settings>
      </iron-pages>
    </app-header>
  </app-header-layout>
</app-drawer-layout>

In side both expenses-dashboard and expenses-settings is just placeholder content like:

<link rel="import" href="../../bower_components/polymer/polymer.html">

<dom-module id="expenses-dashboard">
  <template>
    <h1>Dashboard</h1>
  </template>

  <script>
    Polymer({
      is: 'expenses-dashboard'
    });
  </script>
</dom-module>

For <iron-pages selected="[[view]]">, should I be using routeData.view or view? I tried both didnt seem to change anything.

The code on GitHub

Upvotes: 2

Views: 2288

Answers (1)

tony19
tony19

Reputation: 138266

There are a few issues in your code...

  1. Since your <iron-pages>.selected property is bound to an undefined property ("view"), <iron-pages> does not change its page. In your <app-route> data binding, the route parts are parsed into routeData, where the :view slug would be accessed with routeData.view, which is what you should be binding to <iron-pages>.selected:

    <iron-pages selected="[[routeData.view]]">
    
  2. The default selector for <iron-pages> is the page index (i.e., the child index of its contents), so selected would normally have to be an integer between 0 and N - 1 inclusively, where N is the number of child pages. But you could change that. It looks like you want the route to specify the page, which would need to match the name of a page under <iron-pages>. To use "name" as the selected attribute, you'd have to configure <iron-pages>.attrForSelected property:

    <iron-pages selected="foo" attr-for-selected="name">
      <div name="foo"></div>
      <div name="bar"></div>
    </iron-pages>
    

    It might also be a good idea to specify a fallback selection, since the user could accidentally navigate to a URL that doesn't correspond to an existing page (e.g., https://mypage.com/#/non-existent-page).

    <iron-pages selected="[[routeData.view]]" attr-for-selected="name" fallback-selection="foo">
      <div name="foo"></div>
      <div name="bar"></div>
    </iron-pages>
    
  3. In <main-drawer>, you may want to define menuTap() with ES5 syntax (instead of ES6) for maximum browser compatibility.

    Polymer({
      // menuTap(e) { ... }  // <-- ES6
      menuTap: function(e) { ... }
    });
    
  4. Your menuTap() function sets the window.location to a raw path, which noticeably refreshes the page. You could avoid the page refresh by using hash paths, where the intended sub-path of the URL is prefixed with a # (e.g., https://mypage.com/#/settings).

    For hash paths, configure <app-location> to ignore the hash prefix by setting the useHashAsPath property:

    <app-location use-hash-as-path route="{{route}}">
    

    If you prefer to avoid hash paths, you could follow Polymer CLI's app-drawer-template, which uses anchor tags inside an <iron-selector> to set the location, which <app-location> detects and updates its route accordingly. Or you could pass the route in from <expenses-app> and then use this.set('route.path', "dashboard") inside of menuTap().

With the changes above, the following would occur when the user navigates to https://mypage.com/#/dashboard.

  1. <app-location> would set the route property to /dashboard.
  2. <app-route> would parse the route and set routeData.view to dashboard.
  3. <iron-pages> sees routeData.view as dashboard, which matches the specified attribute on a child, which in turn causes only that page to be displayed.

For reference, the guide on Encapsulated Routing with Elements is quite useful.

Upvotes: 4

Related Questions