Run loop madness or am I not smart enough :) please help me debugging


#1

Hey guys!

I need your help once again. The problem is, I can’t provide a good jsFiddle because the problem is related how things work together in my whole app. I’m using ember-cli with ember-data. Ember-cli is on version 0.2.7 and depending libraries are according to this ember-cli version.

I have a catalog which displays all categories as lists and as a nested list all products which belong to the category. Basically it is like:

<ul>
    <li>Category 1
        <ul>
            <li>Product 1</li>
            <li>Product 2</li>
        </ul>
    </li>
    <li>Category 2
        <ul>
            <li>...</li>
        </ul>
    </li>
    <li>Category 3
        <ul>
            <li>...</li>
        </ul>
    </li>
</ul>

Now I want to assign jquery ui draggable to the products. At first I implemented a component for products and each product was rendered with this component. But this solution got really slow after the catalog grew a little. Therefore I changed to just render the catalog view with simple {{#each}} helper. Now catalog render performance is quite ok (not excellent but glimmer will solve this issues magically :smile:) but the assignment of jquery ui draggable does not work always. It seems there is a race condition and sometimes it works and sometimes the view is rerendered and the references to jquery ui draggable are lost. Now I found a solution but I can’t tell why it’s working now. So it would be great if you could help me to debug this issue and give me some tips, tricks and pointers to were to start tracing this issue. My solution looks now as follows:

initializeView: function () {
    var self = this;
    // *** 3 TIMES EMBER RUN NEXT IS ESSENTIAL!!! ***
    // *** OTHERWISE IT JUST WORKS SOMETIMES ***
    Ember.run.next(function () {
        Ember.run.next(function () {
            Ember.run.next(function () {
                self.setupDragging();
                self.setupTooltips();
                self.scrollTo();
            });
        });

    });
},

initializeComponent: function () {
    Ember.run.scheduleOnce('afterRender', this, this.initializeView);
}

The strange thing is, why do I need to call Ember.run.next three times to ensure it’s working? Tell me if I should provide more code. But right now I really don’t know what to present.


#2

To help debugging we should at least know where things go wrong. Now we only see the walkaround solution. If I understand correctly, you want products to be moved within a category, right? If so, then you should create a CategoryComponent and inject the products.

Component:

import 'Ember';

export default Ember.Component.extend({
    attachDraggable : function () {
        var self = this;
        // attach draggable here by using
        this.$('ul').draggable({
            drag : function() {
                self.updateProductModel();
            }
        });
    }.on('didInsertElement'),

    updateProductModel : function (product, newPosition) {
        product.set('position', newPosition);
    }
});

Template

{{#each item in model}}
    {{category products=item.products}}
{{/#each}}

#3

The problem is, I really don’t know where things go wrong… It seems that somewhere a run loop (or re-render) is triggered after I setup all the jquery draggable bindings. This re-render seems to destroy all the jquery draggable bindings. And yes of course it would make more sense to use components but components made the list quite slow (rendering takes several seconds).

So it would be interesting if there is a way to see were a re-render is triggered and to add jquery draggable bindings after the “last” re-render. Or maybe just some way to figure out were it could go wrong. This seems to be a “hard-to-trace-issue” (at least for me :smile: )