21

Is there any event fired stating the transition/rendering has completed (and the dom is visible/ready).

setupcontroller/activate are before the dom is built/rendered

didInsertElement gets fired only the first time when I've already inserted an element and I'm just switching the model out underneath it.

What I'm really looking for is the transition is complete event

I guess I can do this, but I was kind of hoping it was already built in...

Ember.Router.reopen({
  didTransition:function(infos) {
     this._super(infos);
     console.log('transition complete');  
  }
});

Even cooler would be a callback to the route that the transition completed for it, I may have to write this and submit a pull request.

Kingpin2k
  • 47,277
  • 10
  • 78
  • 96
  • have a look at this gist https://gist.github.com/machty/5723945 the changes described there are already in RC6 – intuitivepixel Jul 02 '13 at 23:08
  • 1
    Yes, I did see that. It partially helped, the only problem being I could run code after the transition, but that still isn't after it's been inserted into the dom. – Kingpin2k Jul 12 '13 at 04:47

4 Answers4

30

There are a couple of different ways you can solve this

didInsertElement

This is fired when the view is inserted on the first time, but not fired if the model is switched out under the view (because Ember likes to reuse items, since it's cheaper than rebuilding the entire DOM). Example below.

Simple

If you only need to do it once, the first time the view is inserted, use didInsertElement

App.FooView = Em.View.extend({
  setupSomething: function(){
    console.log('the dom is in place, manipulate');
  }.on('didInsertElement')
});

Example: http://emberjs.jsbin.com/wuxemo/1/edit

Complex

If you need to schedule something after the DOM has been rendered from the route itself, you can use schedule and insert it into the afterRender queue.

App.FooRoute = Em.Route.extend({
  setupController: function(controller, model){
    this._super('controller', model);
    Ember.run.schedule('afterRender', this, function () {
      //Do it here
    });
  }
});

Example: http://emberjs.jsbin.com/wuxemo/2/edit

Transition promise

The transition's promise will complete before it's finished rendering items. But it gives you a hook for when it's done with fetching all of the models and controllers and hooking them up.

If you want to hook up to the transition event you can do it like so:

var self = this;
transitionTo('foo').then(function(){
    Ember.run.schedule('afterRender', self, function () {
          //Do it here
    });
})
Community
  • 1
  • 1
Kingpin2k
  • 47,277
  • 10
  • 78
  • 96
  • 1
    FYI: Passing anonymous functions into `scheduleOnce` will not schedule it "once", since it's checking the function reference to see if it's already scheduled. You'll need to define the function somewhere static (like on the object) so it's: `Ember.run.scheduleOnce('afterRender', this, this.myStaticFunction)` – Ben Lesh Aug 11 '14 at 17:08
  • 2
    Yes, great point, at the time when I wrote that I was unaware of that, and haven't done enough cleanup in my answers. Great point, and updated to not give the wrong impression. This is true as well with debounce and throttle (and often misunderstood) – Kingpin2k Aug 12 '14 at 13:11
  • can components can listen to renderComplete events? – SuperUberDuper Mar 16 '15 at 13:30
12

The afterModel hook might work for you:

App.MyRoute = Ember.Route.extend({
  afterModel: function(model, transition) {
    transition.then(function() {
      // Done transitioning
    });
  }
});

I tested this using RC-7 with routes that both do and don't have dynamic segments (i.e., a route with a model and a route without a model). It seems to work either way.

See this JSBin for an RC-6 example:
  Output: http://jsbin.com/OteC/1/
  Source: http://jsbin.com/OteC/1/edit?html,js

Rocky
  • 121
  • 3
  • 1
    This promise resolve is most excellent for knowing that the transition is complete. Perfect for calling controller properties within views and knowing you have the right model. – Matthew Blancarte Nov 22 '13 at 23:04
  • Thank you, exactly what I needed. Working great in Ember 1.7.0. – rog Oct 16 '14 at 05:56
  • I could kiss you right now. My afterModel was making model changes to the a parent controller but the template wasn't updating the new data. I moved the change to the transition.then and everything is all better. – colsen Oct 01 '15 at 21:17
  • 1
    Doesn't work in latest Ember as far as I can see. If in afterModel(), you try to access the DOM element that is in the router template it does not exist – Epirocks Aug 04 '16 at 12:09
3

setupController is the last thing that the Router calls before finalizing the transition. And if it completes without errors, as far as Ember is concerned the transition is complete. You actually see this in action by enabling LOG_TRANSITIONS_INTERNAL.

At that point, It doesn't matter if the controller has thrown an error, view has thrown an error, etc. The router has completed transitioning into the target route.

So setupController is the last place in terms of the Router that corresponds to didTransition.

When the content/model backing the controller changes on an existing View, the bindings kick in. Most of the changes that happen to the view at that point are via Metamorphing.

The closest place I can think of to hook into would be View.render which pushes changes into the RenderBuffer. But you still need to account for Metamorphing via mixins that happens here.

Darshan Sawardekar
  • 5,065
  • 2
  • 21
  • 31
  • To be pedantic, I would say that "`setupController` is the first thing that the Router calls after finalizing the transition", although I suppose it depends on the precise semantics you assign to the word "finalize". –  Jun 05 '15 at 08:05
1

didTransition does exist as you hoped -- but its an action and not a hook

XXRouter
actions: {
    didTransition: function() {
        this.controller.set("hasTransitioned", true); // or whatever is needed?!
        return true; // Bubble the didTransition event
    },
}


XXController    
observeTransition: function() {
    alert('complete Transition');
}.observes('hasTransitioned'),
Gabe Rainbow
  • 3,658
  • 4
  • 32
  • 42