2012-04-03 3 views
2

У меня есть приложение Ember.js, которое имеет модель Checklist, где в каждом контрольном списке есть много Checkitems. (Вариант классического приложения ToDo, но с несколькими TodoLists.)Каков правильный подход к обновлению привязок jQuery в представлении Ember.js?

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

Контрольно-пропускные пункты с правой стороны перетаскивают сортировку. Я использую this html5sortable library для обработки сортировки перетаскивания. Это похоже на классическую версию jQueryUI, но менее неуклюжий.

При первоначальной загрузке приложения сортируемый список работает нормально. Однако, если список контрольно-пропускных пунктов изменяется (либо потому, что контрольная точка отмечена как полная, добавлена ​​новая контрольная система, а изменения в существующем контрольном элементе сохранены или выбран другой контрольный список слева), привязка к html5sortable будет потеряна.

Когда приложение сначала загружает, у меня есть вид называется App.CheckitemsPendingTableView:

App.CheckitemsPendingTableView = Ember.View.extend({ 
    templateName: 'app/templates/checkitems/checkitemsPendingTable', 
    classNames: ['checkitems-list', 'sortable', 'list'], 
    tagName: 'ul', 

    didInsertElement: function() { 
    this._super(); 
    $('ul.sortable').sortable(); 
    console.log('CheckitemsPendingTableView has been inserted in the DOM and is bound to sortable. At this point, drag-sorting of the list is working fine.'); 
    } 
}); 

Соответствующий шаблон называется checkitemsPendingTable.handlebars и это выглядит следующим образом:

{{#each content}} 
    {{view App.CheckitemSingleView checkitemBinding="this"}} 
{{/each}} 

И для хорошей меры, контроллер который подает атрибут content для этого вида: App.checkitemsController.remainingItems:

App.checkitemsController = Ember.ArrayProxy.create({ 
    content:[], 

    ...snip... 

    remainingItems: function() { 
    var checkitems = this.get('content'); 
    var sortedCheckitems = checkitems.filterProperty('isDone', false).sort(function(a,b) { 
          return a.get('position') - b.get('position'); 
          }); 
    return sortedCheckitems; 
    }.property('[email protected]'), 

    ...snip... 

}); 

Атрибут содержание checkitemsController движет checklistsController:

App.checklistsController = Ember.ArrayProxy.create({ 
    content: App.store.findAll(App.Checklist), 

    selectedChanged: function() { 
    var checklist = this.get('selected'); 
    var checkitems = checklist.get('checkitems'); 
    App.checkitemsController.set('checklist', checklist); 
    App.checkitemsController.set('content', checkitems); 
    }.observes('selected') 
}); 

(Вы, возможно, заметили, что этот контроллер тянет данные из бэкэнд Rails через Ember-данных. Это не должно иметь значения для текущей проблемы.)

Вид для меню левой стороны называется checklistsView. Она имеет вид ребенка под названием checklistSingleView, что визуализируется для каждой из контрольных списков:

App.ChecklistSingleView = Ember.View.extend({ 
    templateName: 'app/templates/checklists/checklistSingle', 
    classNames: ['menu-item'], 
    tagName: 'tr', 

    ...snip... 

    chooseList: function() { 
    var checklists = App.checklistsController.get('content'); 
    checklists.setEach('isActive', false); 
    var checklist = this.get('checklist'); 
    checklist.set('isActive', true); 
    App.checklistsController.set('selected', checklist); 
    } 

    ...snip... 

}); 

И, наконец, соответствующий шаблон checklistSingle.handlebars содержит ссылку, которая привязана к chooseList путем действия:

<a href="#" {{action "chooseList"}}>{{checklist.name}}</a> 

Итак, все вышеописанное работает блестяще ... до тех пор, пока пользователь не поменяет на ul контрольных пунктов справа. В этот момент привязка к html5sortable потеряна, и я не могу найти удобное место для ее обновления.

Проблема заключается в том, что didInsertElement не вызывается снова для представления, которое генерирует это значение ul (т. Е. CheckitemsPendingTableView). Когда атрибут checklistController content изменяется, дочерние представления послушно настраиваются, чтобы отображать выбранный в настоящий момент список контрольных элементов. Однако исходное связывание с sortable() теряется, и нет явного крючка для повторного связывания с sortable() через jQuery.

Я не могу повторно привязать дочерний вид CheckitemsPendingTableView, так как это будет повторяться для каждого экземпляра checkitem в выбранном списке.Я не могу отпереть от контроллеров или моделей, так как они будут пытаться связываться до завершения обновления DOM.

Я уверен, что я просто думаю об этом неправильно. Я новичок в Ember.js (если это не совсем очевидно), и я стараюсь понять, как этот случай правильно обрабатывается.

UPDATE

Я решил эту проблему, добавив следующую функцию и наблюдателя на App.CheckitemsPendingTableView:

resetSortableTable: function() { 
    $('.sortable').unbind('sortable'); 
    $('.sortable').sortable(); 
    console.log('Sort reset by CheckitemsPendingTableView'); 
    }, 

itemsChanged: function() { 
    console.log('itemsChanged caught in CheckitemsPendingTableView'); 
    // flush the RunLoop so changes are written to DOM 
    Ember.run.sync(); 
    Ember.run.next(this, function() { 
     this.resetSortableTable(); 
    }); 
    }.observes('[email protected]') 

Я основано мое решение на this answer. Я немного обеспокоен тем, что это не отличное решение, поскольку, похоже, он делает предположения о завершении DOM во время итерации цикла запуска.

ответ

0

Whoa! Вид детального вопроса ...

Я думаю, что ваш вопрос исходит из html5sortable plugin: он использует метод JQuery bind для прикрепления обработчиков непосредственно к живым элементам. Поскольку эти элементы исчезают/развиваются под контролем Ember, привязка теряется.

Плагин должен лучше использовать метод JQuery on для привязки обработчиков, как указано in the documentation.

+0

Спасибо, что прочитали, Майк! Я подумал, что я иду с 'on', но нашел временное решение (см. Обновление моего исходного вопроса). – sirvine

+0

Добро пожаловать. В самом деле, обходной путь, который вы нашли, звучит действительно дерьмово ... :-P –

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