1
votes

if i wanted to call a jquery plugin (which inserts a table into the dom, for example) after a view has been rendered, are there a possibilities except doing this with window.setTimeout()?

This code does the job (1ms timeout; thats weird):

Route.HomeRoute = Ember.Route.extend({
        renderTemplate: function() {

            this.render("home");   // render the home view

            window.setTimeout(function() {
                $(".tables").insertTables();    // this would add a table
            }, 1);

        }
    })

But this code doesn't work:

Route.HomeRoute = Ember.Route.extend({
        renderTemplate: function() {

            this.render("home");   // render the home view

            $(".tables").insertTables();    // this would add a table

        }
    });

I know that there's Ember.View.didInsertElement(), but therefore i have to set a callback on the parent View, and was just wondering, why the code example above doesn't work as expected.

Many thanks!

2

2 Answers

2
votes

I don't know wether my answer is 100% accurate, but i guess this is how it can be explained:

I guess the problem is, that you think that the render() method does its job synchronously. But this is not the case. Instead it schedules the rendering of the HomeView. The rendering is scheduled into the RunLoop of Ember. In the second example your code schedules the rendering and then immediately tries to access its DOM Elements (i guess .tables is part of the home template). But the View is not rendered at this time! The first example works, because there is 1ms timeout involved. During this timeout the Ember RunLoop will kick in and starts its magic. It performs the rendering and afterwards when the CPU is free again, your timeout function can be called.

Actually what you want to do here is: do something on my DOM, when the View was successfully rendered. This can be done in Ember, without the use of setTimeout. The following code accesses the RunLoop and schedules a function to be performed at the end of the RunLoop.

Ember.run.next(function() {
     $(".tables").insertTables();    // this would add a table
});

Here is an article on the RunLoop, which is important to understand, if you want to understand those details of Ember: - Article by machty

Last but not least: It seams totally awkward to do such DOM Manipulation in the Route. Your Route should always be free, of such things. Element and Selectors and jQuery Plugins should only be used in the View layer. Everything else seems bad. Maybe you want to share more details about why you chose this approach? There is likely a better solution that this one.

0
votes

The reason why the second example doesn't work is probably due to the Ember.js Run Loop. this.render schedules the dom insertion for later in the current run loop.

DOM insertion is done at the end of the run loop, and by using setTimeout, you are calling the plugin after the run loop ends, therefore guaranteeing that the template was injected into the DOM. (no need for the 1ms, 0ms would probably work)

You might say this run loop thing is very complicated, especially for an Ember.js beginner. The thing is, ideally, it is supposed to be transparent to the app developer. The reason why you are encountering its side effects, is because DOM manipulation should not be handled in the router.

My first reaction was to tell you to use didInsertElement, or any code or hook inside the View, because that's where DOM manipulation should happen. But it seems you are aware of that and cannot use it for some reason (which I can't confirm or deny because I don't have enough information).

My advice to you, try your best to do it in didInsertElement.