我有一个Ember.js应用程序,它有一个Checklist
模型,其中每个检查表有很多Checkitems
。 (经典ToDo应用程序的一个变体,但有多个待办事项列表。)在Ember.js视图中刷新jQuery绑定的正确方法是什么?
在最上面的视图中,用户看到左侧的所有可用清单列表。当选中一张清单时,相应的检查项显示在右侧。
右侧的checkitems是可拖曳排序的。我使用this html5sortable library来处理拖曳排序。这就像经典的jQueryUI版本,但不那么笨重。
初次加载应用程序时,可排序列表正常工作。但是,如果检查项目列表发生更改(或者因为checkitem被标记为完成,添加了新的checkitem,保存了对现有检查项目的更改或左侧选择了其他检查列表),则绑定到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后端拉动其数据。虽然这对当前问题应该没有关系。)
左侧菜单的视图被称为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
属性发生更改时,子视图将尽职调整以反映当前选定的checkitems列表。但是,与sortable()
的原始绑定丢失,并且没有明显挂钩通过jQuery重新绑定到sortable()
。
我无法重新绑定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完成做出了假设。
感谢您的阅读,Mike!我考虑用'on'进行,但同时找到了解决方法(请参阅我的原始问题的更新)。 – sirvine 2012-04-03 06:46:02
不客气。事实上,你找到的解决方法听起来真的很糟糕...... :-P – 2012-04-03 07:02:01