У меня есть приложение 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 во время итерации цикла запуска.
Спасибо, что прочитали, Майк! Я подумал, что я иду с 'on', но нашел временное решение (см. Обновление моего исходного вопроса). – sirvine
Добро пожаловать. В самом деле, обходной путь, который вы нашли, звучит действительно дерьмово ... :-P –