Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

_routePageChanged running twice #129

Open
1 of 8 tasks
ansarizafar opened this issue Jul 11, 2016 · 22 comments
Open
1 of 8 tasks

_routePageChanged running twice #129

ansarizafar opened this issue Jul 11, 2016 · 22 comments

Comments

@ansarizafar
Copy link

ansarizafar commented Jul 11, 2016

Browsers Affected

  • Chrome
  • Firefox
  • Safari 9
  • Safari 8
  • Safari 7
  • Edge
  • IE 11
  • IE 10

Here is my code

<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/app-route/app-location.html">
<link rel="import" href="../bower_components/app-route/app-route.html">
<link rel="import" href="../bower_components/app-layout/app-drawer-layout/app-drawer-layout.html">
<link rel="import" href="../bower_components/app-layout/app-drawer/app-drawer.html">
<link rel="import" href="../bower_components/app-layout/app-scroll-effects/app-scroll-effects.html">
<link rel="import" href="../bower_components/app-layout/app-header/app-header.html">
<link rel="import" href="../bower_components/app-layout/app-header-layout/app-header-layout.html">
<link rel="import" href="../bower_components/app-layout/app-toolbar/app-toolbar.html">
<link rel="import" href="../bower_components/paper-icon-button/paper-icon-button.html">
<link rel="import" href="../bower_components/paper-menu/paper-menu.html">
<link rel="import" href="../bower_components/paper-item/paper-item.html">
<link rel="import" href="../bower_components/paper-menu-button/paper-menu-button.html">
<link rel="import" href="../bower_components/neon-animation/neon-animated-pages.html">
<link rel="import" href="../bower_components/neon-animation/neon-animatable.html">
<link rel="import" href="../bower_components/neon-animation/animations/slide-from-left-animation.html">
<link rel="import" href="../bower_components/neon-animation/animations/slide-right-animation.html">

<link rel="import" href="../bower_components/iron-selector/iron-selector.html">
<link rel="import" href="my-icons.html">

<dom-module id="my-app">

  <template>

    <style>
      :host {
        display: block;
        --app-primary-color: #4CAF50;
        --app-secondary-color: black;
      }

      app-header {
        background-color: var(--app-primary-color);
        color: #fff;
      }

      app-header paper-icon-button {
        --paper-icon-button-ink-color: white;
      }

      .drawer-list {
        margin: 0 20px;
      }

      .drawer-list a {
        display: block;
        padding: 0 16px;
        line-height: 40px;
        text-decoration: none;
        color: var(--app-secondary-color);
      }

      .drawer-list a.iron-selected {
        color: black;
        font-weight: bold;
      }

      .drawer-list a.subroute {
        padding-left: 32px;
      }
    </style>

    <app-location route="{{route}}"></app-location>
    <app-route route="{{route}}" pattern="/:page" data="{{routeData}}" tail="{{subroute}}"></app-route>
    <app-drawer-layout fullbleed force-narrow="true">
      Drawer content
      <app-drawer id="menu" swipe-open>
        <app-header>
          <app-toolbar>
            <iron-icon icon="move-to-inbox"></iron-icon> Restock
          </app-toolbar>
        </app-header>
        <iron-selector selected="{{routeData.page}}" attr-for-selected="name" class="drawer-list"
          role="navigation">
          <a name="" drawer-toggle href="/">Home</a>
          <a name="signup" drawer-toggle href="/signup">Create a free account</a>
          <a name="login" drawer-toggle href="/login">Login</a>
          <a name="about" drawer-toggle href="/about">About</a>
        </iron-selector>
      </app-drawer>

      <!-- Main content -->
      <app-header-layout has-scrolling-region>

        <app-header condenses reveals effects="waterfall">
          <app-toolbar>
            <paper-icon-button icon="menu" drawer-toggle></paper-icon-button>
            <div title>Restock</div>
            <paper-menu-button horizontal-offset=- 18>
              <paper-icon-button icon="more-vert" class="dropdown-trigger"></paper-icon-button>
              <paper-menu class="dropdown-content">
                <paper-item>Signup</paper-item>
                <paper-item>Login</paper-item>
                <paper-item>Help</paper-item>
              </paper-menu>
            </paper-menu-button>
          </app-toolbar>
        </app-header>

        <neon-animated-pages selected="[[routeData.page]]" fallback-Selection="notfound" attr-for-selected="name" entry-animation='slide-from-left-animation'
          exit-animation='slide-right-animation'>
          <neon-animatable name=''>
            <home-page name=""></home-page>
          </neon-animatable>
          <neon-animatable name='signup'>
            <signup-page name="signup"></signup-page>
          </neon-animatable>
          <neon-animatable name='login'>
            <login-page name="login"></login-page>
          </neon-animatable>
          <neon-animatable name='notfound'>
            <notfound-page name="notfound"></notfound-page>
          </neon-animatable>
          </neon-animated-page>

      </app-header-layout>

    </app-drawer-layout>
  </template>

  <script>

    Polymer({

      is: 'my-app',
      user: 'Zafar',
      properties: {

      },

     observers: [
        '_routePageChanged(routeData.page)'
      ],

      _routePageChanged: function(page) {
  console.log(page);

switch (page) {
case '':
case 'home':
this.importHref(this.resolveUrl('home.html'), null, null, true);
break;
case 'signup':
this.importHref(this.resolveUrl('signup.html'), null, null, true);
break;
case 'login':
this.importHref(this.resolveUrl('login.html'), null, null, true);
break;
default:
this.importHref(this.resolveUrl('notfound.html'), null, null, true);

}
      },
    });

  </script>

</dom-module>
@rictic
Copy link
Collaborator

rictic commented Jul 14, 2016

Can you give more info here? What values of page are you seeing, and in what order? How do these values correspond to the URL?

@ansarizafar
Copy link
Author

Whenever I click a link, _routePageChanged function is running twice. For example If I click signup link, The page value signup appears twice in console.

@JanGunzenhauser
Copy link

It is running twice because it changes twice, because a click on e.g. /signup link triggers

  1. a select of name="signup" in selected="{{routeData.page}}", because of two-way-binding
  2. a path change because of its href

Try using a one-way-binding like you do on the animated pages.

@kshep92
Copy link

kshep92 commented Dec 10, 2016

Running a similar example and with the only two-way binding being the {{route}} property the observer fires twice when using hash URLs.

<app-location route="{{route}}" use-hash-as-path></app-location>
<app-route route="[[route]]" pattern="/:page" data="{{data}}" tail="{{tail}}"></app-route>
.
.
.
observers: ['_routePageChange(data.page)'],
_routePageChange: function(e) {   
    console.log('_routePageChange'); //Prints twice for #/home and #/about
}

@kshep92
Copy link

kshep92 commented Dec 10, 2016

Here's a more complete example. Switched to traditional no-hash routing as well and still getting the observer running twice. My workaround was to listen for the window.location-changed event fired by app-location.

<link rel="import" href="bower_components/app-route/app-location.html" >
<link rel="import" href="bower_components/app-route/app-route.html" >
<dom-module id="blog-app">
    <template>
        <app-location route="{{route}}"></app-location>
        <app-route
            route="{{route}}"
            pattern="/:page"
            data="{{pageData}}"
            tail="{{pageTail}}">
        </app-route>
        <ul>
            <li>
                <a href="/home">Home</a>
            </li>            
            <li>
                <a href="/about">About</a>
            </li>
        </ul>
        
    </template>
    <script>
        Polymer({
            is: 'example-app',
            properties: {
                pageData: Object
            },
            observers: ['_pageDataChange(pageData.page)'],
            attached: function() {
                window.addEventListener('location-changed', function() {
                    console.log('new location:' + this.pageData.page); //Fires once
                }.bind(this));
            },
            _pageDataChange: function(e) {
                console.log('_pageDataChange'); //Fires twice on route change
            }
        });
    </script>
</dom-module>

@virusakos
Copy link

virusakos commented Dec 10, 2016

This is happening in Safari as well (and I suppose in all browsers).

Steps to replicate:

  1. polymer init with starter-kit
  2. Add console.log('_routePageChanged | page = ', page); in _routePageChanged: function(page) in my-app.html

Open Safari, show web inspector and you will immediately see:

_routePageChanged | page = "view1"
_routePageChanged | page = "view1"

Navigate to view2:

_routePageChanged | page = "view2"
_routePageChanged | page = "view2"

etc

What I ended up doing to avoid this issue is this:
I defined a new property

pageLoaded: {
  type: String,
  value: ''
}

and changed _routePageChanged: function(page) to

_routePageChanged: function (page) {
  if (this.pageLoaded !== page) {
    this.page = page || 'view1';
    this.pageLoaded = this.page;
  }
}

But it feels 'hacky' and have no idea yet what kind of problems I will be having with this.
The event is still firing twice.

@abridger
Copy link

Not sure if this is the right strategy, but we had this problem and it was hugely affecting our page tracking. Our _viewChanged observer now wraps a debounce method to collapse multiple requests, which seems to have resolved the problem.

_viewChanged (view) {
        this.debounce('viewChanged', () => {
            // Tracking events
        });
}

@jfrazzano
Copy link

jfrazzano commented Dec 15, 2016 via email

@daniele-orlando
Copy link

What's the status of the fix for this bug? I can still reproduce it on Google Chrome.

@Thkasis
Copy link

Thkasis commented Apr 17, 2017

Any update on this? I seem to have the same issue

@jurerick
Copy link

How it is going?

@jukbot
Copy link

jukbot commented May 19, 2017

yep how it's update ?

@ghost
Copy link

ghost commented Jun 8, 2017

I have the same buf. I'm fixed this bug by just calling routeChange and format url as i need, it is running only once on change url

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

 observers: [
         '_routeChanged(route)',
 ],

 _routeChanged: function (r) {
         console.log(r.path);
         var id = r.path.split("/")[2];
         var tab = r.path.split("/")[3];
         if(id  != null)
               this._routeIdChanged(id);
        this._routeTabChanged(tab);
}, 

@johnlim
Copy link

johnlim commented Aug 30, 2017

Hi, just realised I'm also encountering this issue. Is there any update on this?

@kshep92
Copy link

kshep92 commented Aug 30, 2017

@johnlim guess not. Maybe in Polymer 3.0? I've always said that Polymer needed a fully featured routing system complete with life cycle hooks (before callback, after callback) and maybe we'll get that in addition to a resolution to this issue.

@tekkamanendless
Copy link

I've been using @abridger's debounce workaround for the past year, and that's been good enough for me. If my workflow becomes more complicated that this gets in the way again, maybe I'll poke around and see if I can submit a patch. That's unlikely at this stage, however.

@markbrocato
Copy link

+1 We're running into this as well.

@HJK181
Copy link

HJK181 commented Feb 22, 2018

Still nothing new after more than one and a half year?

@sundar-rajavelu
Copy link

Even after all these months, for reasons unknown, the 'routeData.page' is still firing twice.
So, I did this:
`

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

<app-route
  route="{{route}}"
  pattern="/:page"
  data="{{routeData}}" 
  tail="{{subroute}}"
  query-params="{{queryParams}}">
</app-route>

 ....

 static get observers() {
    return [
      '_routePathChanged(route.path)',
    ];
  }

  _routePathChanged(path) {
    
    console.log('routeData.page: ', this.routeData.page);
    console.log('queryParams: ', this.queryParams);

    
  }

`

@sebs
Copy link

sebs commented Jun 27, 2018

  1. Juli 2016

no time for that

@jsilvermist
Copy link

jsilvermist commented Jun 27, 2018

With Polymer 3 I'm finding the pwa-helpers router a sufficient replacement in most cases.

App shell

// https://github.com/Polymer/pwa-helpers/blob/master/router.js
import { installRouter } from 'pwa-helpers/router.js';

constructor() {
  super();

  // Register location changed listeners
  installRouter((location) => this._locationChanged(location));
}

_locationChanged(location) {
  // Remove root-path from route
  const prefixRegex = new RegExp('^' + this.rootPath);

  // Get path from router
  const path = window.decodeURIComponent(location.pathname).replace(prefixRegex, '');

  // Parse path to create route
  this.route = path.split('/').filter((item) => item !== '');
}

Mixin shared between all routing views

_routeChanged(route) {
  // Default to '_default' when `route` array is empty.
  this.page = route.length > 0 ? route[0] : '_default';
}

// Compute subroute for sub-views
// <my-view route="[[_bindSubroute(route, 'foobar')]]"></my-view>
_bindSubroute(route, uri) {
  return route.length > 1 && route[0] === uri ? route.slice(1) : [];
}

// Compute active for sub-views
// <my-view active="[[_bindActive(route, 'foobar')]]"></my-view>
_bindActive(route, uri) {
  return route.length > 0 && route[0] === uri;
}

For query parameters, there's no end of solutions available for parsing location.search so I'll just leave that for a Google search.

@sebs
Copy link

sebs commented Jun 27, 2018

This is a close ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests