我有一個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