Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do something when ember is done with DOM updates

I want to do stuff when ember bindings have synchronized and the DOM is again up to date.

I have tried with a callback from the function that manipulates the binded model, DOM is not updated when callback is executed.

I have tried with an observer directly on the model, DOM is not updated when the observer is executed.

I have tried with an observer on the binding, DOM is not updated when the observer is executed.

e.g.

App.view = Ember.View.extend({
    modelBinding: 'App.model',
    modelChanged : function() {
        window.scrollTo(0, document.body.scrollHeight);
    }.observes('model'),

    getMore: function(event) {
        App.set('model', "somethingnew");
    }
});

When I fire the "gotMore", I update the model, and when the model is updated and its changes have been rendered I want to scroll down.

In none of the ways I've tried have I been able to get the new scrollHeight. It is set a few ms after these events.

Here's an example on jsFiddle: http://jsfiddle.net/kcjzw/15/

like image 264
abaelter Avatar asked May 21 '12 13:05

abaelter


2 Answers

The correct way to do this is documented here:

http://emberjs.com/api/classes/Ember.run.html#method_next

modelChanged : function() {
  Ember.run.scheduleOnce('afterRender', this, function() {
    window.scrollTo(0, document.body.scrollHeight);
    $('body').append('New scroll height: '+document.body.scrollHeight);
  });
}.observes('content')
like image 123
atomkirk Avatar answered Sep 18 '22 12:09

atomkirk


Use Ember.run.next

https://github.com/emberjs/ember.js/blob/master/packages/ember-metal/lib/run_loop.js#L531-566

App.view = Ember.View.extend({
    modelBinding: 'App.model',
    modelChanged : function() {
        Ember.run.next(myContext, function(){
            // code to be executed in the next RunLoop, which will be scheduled after the current one
            window.scrollTo(0, document.body.scrollHeight);
        });
    }.observes('model'),

    getMore: function(event) {
        App.set('model', "somethingnew");
    }
});

Update

Take a look at this: http://jsfiddle.net/ud3323/hZ7Vx/

What you need is to run your code after the runloop that renders the Ember.CollectionView that the {{each}} helper would create.

JavaScript:

App = Ember.Application.create();

App.model = Ember.Object.create({
    items: [1]
});

App.view = Ember.Handlebars.EachView.extend({
    contentBinding: 'App.model.items',

    itemViewClass: Ember._MetamorphView.extend({
        templateName: 'the_template'
    }),

    modelChanged : function() {
        Ember.run.next(this, function(){
            window.scrollTo(0, document.body.scrollHeight);
            $('body').append('New scroll height: '+document.body.scrollHeight);
        });
    }.observes('content'),

    theAction: function(event) {
        App.controller.doStuffToModel();
    }
});

App.controller = Ember.Object.create({
    doStuffToModel : function() {
        App.model.set('items', [1,2,3,4,5]);
    }
});

Handlebars:

<script type="text/x-handlebars" data-template-name="the_template">
    <div style="height:200px;"></div> 
</script>

<script type="text/x-handlebars">
    {{view App.view}}
</script>​ 
like image 22
Roy Daniels Avatar answered Sep 22 '22 12:09

Roy Daniels