2016-05-08 2 views
0

Я пытаюсь создать простой компонент Ember, который обертывает плагин jQuery UI Sortable. К сожалению, у меня проблема с шаблоном компонента, когда sortable отменен, а модель обновлена ​​вручную. Похоже, что DOM не отражает состояние модели. Я не могу найти, почему.Проблема с шаблоном Ember с jQuery sortable

Я создал JS Bin, чтобы представить эту проблему. Когда вы меняете позицию позиции, первый из них должен быть удален. К сожалению, это работает случайным образом.

Что не так с этим кодом?

+0

У меня нет ответа на ваш вопрос, но я могу хотя бы предложить POV, с которым вам следует рассмотреть возможность анализа вашей ситуации. Плагин JQuery UI Sortable основан на прямой манипуляции с DOM, которая будет выполняться как обратные вызовы, которые регистрируются им при пожаре на пользователях событий мыши. Ember с другой стороны использует HTMLbars, который также имеет DOM-манипуляционную логику, которая намного сложнее и должна быть погружена в понимание такого поведения. Вам следует избегать прямого манипулирования DOM и мутацией массива 'content' на компоненте. Это разумный способ делать вещи. – canufeel

+0

Я думаю, я также должен добавить, что если вы хотите получить это с самого начала, вы должны «отвязать» массив 'content' до того, как будете на самом деле мутировать, чтобы вы не попали в адвентирующий ад. – canufeel

+0

@ canufeel, вы правы, это проблема DOM. Когда я смоделирую обновление в компоненте, как в этом [JS Bin] (http://emberjs.jsbin.com/huciqinoho/edit?html,js,output), тогда он работает. Однако я думаю, что, должно быть, был какой-то способ Эмбер. Может быть, это проблема с Glimmer, которая не может сделать правильный diff после того, как DOM был изменен jQuery UI? – Lucas

ответ

0

Вот ваш JS Bin сортировкой компонент:

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); 
    }); 
    } 
}); 

И тогда это ваш JS Bin updated с кодом из ember-ui-sortable repo на следующее:

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'); 
    } 
}); 

Как вы видите, довольно немного дополняет ваш оригинал, поэтому вы можете взглянуть на то, что вы пропустили, и, надеюсь, это вам поможет. Возможно, было бы неплохо установить этот компонентный аддон через ember-cli, но также посмотреть на конкурирующие решения, например ember-sortable и другие, используя что-то вроде ember-observer.

+0

Спасибо за ответ, но я не думаю, что отсутствующий наблюдатель является проблемой здесь. Я действительно начал с кода из вашего плагина (я только что добавил «отменить» вызов после того, как пользователь перестает манипулировать вызовом обновления элемента и модели), затем я начал упрощать его поэтапно до кода, который находится в JSBIN. – Lucas

Смежные вопросы