Adam
Adam

Reputation: 693

Ember: Re-render a route's template when the model changes

I've noticed that a route doesn't re-render when the model changes (i.e. transitionTo the same route with a different model). I have some jQuery plugins set up on a particular page and I need them to re-render when the model changes, so it appears as a fresh page.

Is there a way to do this? Perhaps by observing the model's ID and firing a re-render of the route somehow?

Thanks in advance

Upvotes: 2

Views: 3406

Answers (1)

Will Haley
Will Haley

Reputation: 763

I have an ember twiddle that, I believe, does what you're looking for, but first I would like to argue there are no straightforward ways to do what you're asking because it is the opposite of what an SPA is designed to do.

Data binding (without refreshing the view) is typically a boon of an SPA, and the SPA works hard to avoid brute force reloading/refreshing/rerendering the view at all costs. It took me a while to find a solution to your question as it is stated because it seems to go against Ember design principles. Even hooks like route refresh() are meant to update the model and bound data, not reload the template.

Although other people have asked the same question before, it seems that most answers guide users towards not refreshing the whole view. More often than not, the ideal of refreshing the view is an incorrect assumption.

Following previous examples, I would suggest that your goal shouldn't be to refresh the template completely, but rather, figure out how you can make your jQuery plugin better fit in to a Single Page App/client-side JS friendly design and have it reload as a natural part of the route lifecycle.

For instance, maybe the plugin can be reloaded/reset/re-run in afterModel() or somewhere similar.

That said, I was able to accomplish what you asked for using (in my opinion, a hack) Ember.run.later() so that I could invalidate an if block and force the content to rerender. Note, this is typically not what users want since (aside from design principle reasons) it causes UI flicker.

I have a component like so.

/* will-rerender.hbs */
{{#if show}}
    {{yield}}
{{/if}}

And it has a JS file like so.

/* will-rerender.js */
import Ember from 'ember';

export default Ember.Component.extend({
  show: false,

  didReceiveAttrs() {
    this._super(...arguments);

    /* 
      Ugly hack, but we need to reset `show` in
      a separate run loop in order to force the view
      to rerender.
    */

    this.set('show', false);

    Ember.run.later(() => {
      this.set('show', true);
    });
  }
});

You can invoke it like this...

/* your template */
{{#will-rerender cacheKey=model.id}}
   ... your content to rerender ...
{{/will-rerender}}

Whenever the model.id changes the component will invoke didReceiveAttrs() causing show to invalidate and the view to refresh.

As an aside, I think the behavior of switching between models would be much more natural with {{link-to}} rather than calling transitionTo yourself.

Upvotes: 2

Related Questions