Is there an event after the template has been added to the outlet?


#1

I started out using afterRender, which worked pretty well. However, when I transition away and back to this route, only the activate event occurs, but at that point the outlet has not yet been updated with the template. I am trying to grab an element from the page to set up an animation after the transition.

export default Ember.Controller.extend({
    _my_init: function() {
        Ember.run.scheduleOnce('afterRender', this, function() {
            this.send('afterRender');
        });
    }.on('init')
});

export default Ember.Route.extend({                                                                                    
    activate() {
        // The template has not been added to the outlet yet.
    }                                                                                         
    actions: {                                                                                                         
        afterRender: function() {
            $('#my-element').doSomethingCool();
        }
    }
}

#2

You should use the didTransition event on Ember.Route.

Have fun!


How To run scripts after dom has loaded
#3

I ran into an issue with the template waiting on the model objects to be loaded. The event worked great at telling me when the template was added, but there were html comments where the models would get filled in. I worked around it by waiting on the models myself, but I’m wondering if there is a cleaner way to do this, especially since there is a little bit of time between the last model loading and the template getting updated, so I had to add a setTimeout().

Thanks for you help.

export default Ember.Route.extend({
    actions: {
        didTransition: function() {
            var route = this;
            // Element does not exist.
            Ember.run.scheduleOnce('afterRender', this, function() {
                // If the models are already cached, the element exists.
                route.currentModel.get('section_set').then(function(sections) {
                    sections.toArray()[0].get('block_set').then(function() {
                        // 50% chance that the template is updated with the model.
                        setTimeout(function() {
                            // 100% chance that the element exists.
                            animationSetup(route);
                        });
                    });
                });
            });
        }
    }
});

#4

tl;dr; You have to tell your Route what to wait for so it can render the template and then trigger didTransition when you see fit. Not all async operations end before didTransition.

I invite you to read (again) the Routing guide, it explains it all in greater details.


The didTransition event will wait for any async operation returned by the model and setupController hooks.

If there are async operations in your app that occur outside these hooks, your route is not aware of them.

Consider the following example:

//app/routes/index.js

import Ember from 'ember';

export default Ember.Route.extend({
  setupController(controller, model) {
    // Your route is **not** aware of this async operation
    // and will trigger `didTransition` regardless of this operation
    model.find('comment').then((comments)=> controller.set('meh', comments));

    // Because of the return, your route **is** aware of the async operation
    // `didTransition` will occur only **after** the operation is complete.
    return model.find('comment').then((comments)=> controller.set('yay', comments));
  }
});

The template will render regardless of the first model.find(...), while it will only render when the second operation is done and the data is available. Obviously, order doesn’t matter, all ops are async.


#5

Thanks for your help.