2016-05-08 9 views
0

Ich versuche, eine einfache Ember-Komponente zu erstellen, die jQuery UI Sortable Plugin umschließt. Leider habe ich ein Problem mit der Vorlage der Komponente, wenn sortable abgebrochen wird und das Modell manuell aktualisiert wird. Es sieht so aus, als ob das DOM nicht den Zustand des Modells widerspiegelt. Ich kann den Grund nicht finden.Ember Komponente Vorlage Problem mit jQuery sortierbar

Ich habe JS Bin erstellt, um dieses Problem zu präsentieren. Wenn Sie die Position ändern, sollte die erste in der Gruppe entfernt werden. Leider funktioniert es nach dem Zufallsprinzip.

Was ist falsch an diesem Code?

+0

Ich habe keine Antwort auf Ihre Frage, aber ich kann Ihnen zumindest den POV vorschlagen, mit dem Sie Ihre Situation analysieren sollten. Das jQuery UI Sortable-Plugin beruht auf der direkten DOM-Manipulation, die passieren würde, da Callbacks, die von ihm registriert werden, auf Mausereignissen von Benutzern ausgelöst werden. Ember auf der anderen Seite verwendet HTMLbars, die auch eine DOM-Manipulationslogik haben, die viel ausgeklügelter ist und in ein solches Verhalten eingetaucht werden sollte. Was Sie tun sollten, ist eine direkte DOM-Manipulation zu vermeiden und das 'content'-Array auf der Komponente mutieren. Das ist Ember Art Dinge zu tun. – canufeel

+0

Ich denke, ich sollte auch hinzufügen, dass wenn du es gleich von Anfang an willst, du das 'content' Array 'losbinden' solltest, bevor du tatsächlich mutierst, damit du nicht in einer datenbindenden Hölle landest. – canufeel

+0

@canufeel Sie haben Recht, das ist die DOM-Frage. Wenn ich die Aktualisierung in der Komponente wie in [JS Bin] (http://emberjs.jsbin.com/huciqinoho/edit?html,js,output) simuliere, funktioniert es. Aber ich denke, es muss eine Art Ember-Art gegeben haben, es zu tun. Vielleicht ist es ein Glimmer-Problem, das nach DOM, das von jQuery UI verändert wurde, keinen ordentlichen Unterschied machen kann? – Lucas

Antwort

0

Hier ist Ihre JS Bin sortierbar Komponente:

App.MyListComponent = Ember.Component.extend({ 
    tagName: 'ul', 

    didInsertElement() { 
    let opts = {}; 
    opts.update = this.updateList.bind(this); 
    this.$().sortable(opts); 
    }, 

    updateList() { 
    this.$().sortable('cancel'); 
    Ember.run.next(() => { 
     this.get('content').removeAt(0); 
    }); 
    } 
}); 

Und dann ist dies Ihr JS Bin updated mit Code aus dem ember-ui-sortable repo der folgenden:

App.MyListComponent = Ember.Component.extend({ 
    tagName: 'ul', 

    uiOptions: [ 
    'axis', 
    'containment', 
    'cursor', 
    'cursorAt', 
    'delay', 
    'disabled', 
    'distance', 
    'forceHelperSize', 
    'forcePlaceholderSize', 
    'grid', 
    'handle', 
    'helper', 
    'opacity', 
    'placeholder', 
    'revert', 
    'scroll', 
    'scrollSensitivity', 
    'scrollSpeed', 
    'tolerance', 
    'zIndex' 
    ], 

    destroySortable: Ember.on('willDestroyElement', function() { 
    this.$().sortable('destroy'); 
    }), 

    initSortable: Ember.on('didInsertElement', function() { 
    let opts = {}; 

    ['start', 'stop'].forEach((callback) => { 
     opts[callback] = Ember.run.bind(this, callback); 
    }); 

    this.$().sortable(opts); 

    this.get('uiOptions').forEach((option) => { 
     this._bindSortableOption(option); 
    }); 
    }), 

    contentObserver: Ember.observer('content.[]', function() { 
    Ember.run.scheduleOnce('afterRender', this, this._refreshSortable); 
    }), 

    move(oldIndex, newIndex) { 
    let content = this.get('content'); 
    let mutate = this.getWithDefault('mutate', true); 
    let item = content.objectAt(oldIndex); 

    if (content && mutate) { 
     content.removeAt(oldIndex); 
     content.insertAt(newIndex, item); 
    } 

    if(!mutate){ 
     this.attrs.moved(item, oldIndex, newIndex); 
    } 

    }, 

    start(event, ui) { 
    ui.item.data('oldIndex', ui.item.index()); 
    }, 

    stop(event, ui) { 
    const oldIndex = ui.item.data('oldIndex'); 
    const newIndex = ui.item.index(); 

    this.move(oldIndex, newIndex); 
    }, 

    _bindSortableOption: function(key) { 
    this.addObserver(key, this, this._optionDidChange); 

    if (key in this) { 
     this._optionDidChange(this, key); 
    } 

    this.on('willDestroyElement', this, function() { 
     this.removeObserver(key, this, this._optionDidChange); 
    }); 
    }, 

    _optionDidChange(sender, key) { 
    this.$().sortable('option', key, this.get(key)); 
    }, 

    _refreshSortable() { 
    if (this.isDestroying) { return; } 
    this.$().sortable('refresh'); 
    } 
}); 

Wie Sie es sehen Es ist ziemlich viel mehr im Vergleich zu Ihrem Original, so dass Sie sehen können, was Sie verpasst haben und hoffentlich hilft Ihnen das. Es könnte eine gute Idee sein, diese Komponente Addon über Ember-CLI zu installieren, aber auch konkurrierende Lösungen wie ember-sortable und andere zuerst mit etwas wie ember-observer aussehen.

+0

Danke für die Antwort, aber ich denke nicht, dass ein fehlender Beobachter hier ein Problem ist. Ich habe tatsächlich mit dem Code von Ihrem Plugin angefangen (ich habe soeben 'cancel' Call hinzugefügt, nachdem der Benutzer den Item- und Modelupdate-Aufruf manipuliert hat) und dann begann ich es Stück für Stück zu vereinfachen bis zum Code in JSBIN. – Lucas