inDream
inDream

Reputation: 1277

Ember.js - Prevent re-render when switching route

Simplified demo: http://jsfiddle.net/indream/KskXx/
(this demo cannot simulate actual environment with my problem)

For the demo: Hover on photos will show you the caption.
When you clicked a photo, route changed to 'media' with {{linkTo}} helper & lightbox opened.
When clicked place outside lightbox, route changed back to 'feed' by history API & lightbox closed.

My question: Template re-rendered when switch back to 'feed'.
(You can check it by hover on photos as caption lost after that.)
I want to stop this as the app lagged during re-render if there're lots of photos.

Using {{linkTo}} is the reason of problem, please refer to my answer

I've read servel releated question like Ember.js - currentViewBinding and stop re-rendering on every view transition and Animating views before destruction in Emberjs.
But the methods provided seems not work for RC2, I've tried to modify willDestroy event, it works for not re-render but it throwed:
Uncaught Error: Cannot perform operations on a Metamorph that is not in the DOM.
Uncaught Error: NotFoundError: DOM Exception 8
when I switched to another route (i.e. empty nowContent for loading other content). And modify destroyElement isn't work at all.

Here's my code, any ideas to solve my problem?

App.MainView = Ember.View.extend({
  templateName:'main',
  willDestroy: function() {
    if (App.get('destroyCurrentView')){
      this._super();
    }
  }
})
App.PageController = Ember.Controller.extend({
  lightboxClose:function(e){
    if(!e||e.target==e.currentTarget){
      $('#lightbox').hide();
      $('body').removeClass('noscroll');
      history.back();

      App.set('destroyCurrentView',false);
      setTimeout(function(){
        App.set('destroyCurrentView',true);
      }, 500);
    }
});
App.MediaRoute = App.mainRoute.extend({
  enter:function(){
    App.set('destroyCurrentView',false);
    this._super();
  }
});

Upvotes: 1

Views: 2002

Answers (1)

inDream
inDream

Reputation: 1277

I've solved this by changing {{linkTo}} to {{action}} & editing the onUpdateURL handler of location API.

As {{linkTo}} must bubble up to Router while {{action}} not. With this approach, URL still changes for page refresh like Facebook but template will not re-render.

Old Template:

{{#linkTo media feed.id}}
<img src="{{unbound feed.images.low_resolution.url}}" />
{{/linkTo}}

New Template:

<img {{action transitionToMedia feed.id}} src="{{unbound feed.images.low_resolution.url}}" />

Location Handler:

Ember.HistoryJsLocation = Ember.Object.extend({
  onUpdateURL: function(callback) {
    ...
    Ember.$(window).bind('popstate.ember-location-'+guid, function(e) {
      if(window.suppressUpdateURL)return;
      ...
    });
  }
});

Ember.Location.registerImplementation('historyJs', Ember.HistoryJsLocation);

Router Event:

App.mainRoute = Em.Route.extend({
  events: {
    transitionToMedia: function (id) {
      window.suppressUpdateURL = true;
      History.pushState(null, null, '/m/'+id);
      App.pageController.lightbox(id);
    }
  }
});

Lightbox Controller:

Folo.PageController = Em.Controller.extend({
  lightboxClose: function(e){
    ...
    History.back();
    window.suppressUpdateURL = false;
  }
});

Note: Complete code for HistoryJsLocation please refer to Html4 browsers does not support history.pushState and history.replaceState methods of History API from HTML5

Upvotes: 1

Related Questions