Bart Jacobs
Bart Jacobs

Reputation: 9082

How to be notified when a view's template is (re)rendered in Ember?

When a view's template is refreshed due to changes of the model, the didInsertElement hook is not triggered as Ember tries to reuse views as much as possible. This causes some problems for me in that I need to select the first element of a list when the template is rerendered. This happens, for example, when new data is loaded from the server or the application transitions to a different route.

The odd thing is that the view's init method does get called when the application transitions to a different route. The issue is that the template hasn't been rendered at that point, that is, the view hasn't been populated with the new contents of the controller.

In short, how can I be notified after the template of a view has finished rerendering so that I can manipulate the view's contents?

For your information, observing the controller's model is not an option either as the view hasn't been updated by the time the callback is fired.

<script type="text/x-handlebars" id="list">
<div>
  <ul>
  {{#each model.items}}
    <li class="item">
      <p>{{title}}</p>
    </li>
  {{/each}}
  </ul>
</div>
</script>

Update The view needs to be notified when the each block is rerendered. I wanted to use the solution in this question, but it seems that only the each block is rerendered and not the entire template (which is what I want). I could add a trigger event in the each block, but that is very expensive as the custom event would be triggered in each loop of the each block.

Upvotes: 1

Views: 378

Answers (2)

Marcio Junior
Marcio Junior

Reputation: 19128

Maybe this could work:

App.ListView = Ember.View.extend({
    templateName: 'list',
    contentChanged: function() {
        Ember.run.scheduleOnce('afterRender', this, 'selectFirstElement')
    }.observes('controller.content.[]'),
    selectFirstElement: function() {
        // for simplicity
        this.$('li:first').addClass('selected');
    }
});

Using observes('controller.content.[]') make the contentChanged function be called, if some change is performed in the controller content. To don't get that function called a lot of times in the same runloop we use the Ember.run.scheduleOnce('afterRender', ...), so selectFirstElement is called just once, and because it's scheduled in the afterRender queue, you can manipule the dom.

Live demo http://jsfiddle.net/marciojunior/4b2V3/

Upvotes: 4

Alex Navasardyan
Alex Navasardyan

Reputation: 536

App.MagicView = Ember.View.extend({
  doMagic: function() {
    // magic goes here
  }.on('didInsertElement');
});

Update: I see now. Here's my brain dump: http://emberjs.jsbin.com/URidoBi/3/edit. Not the cleanest way, but should get you around the problem.

Upvotes: 0

Related Questions