2012-04-03 34 views
2

我有一個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完成做出了假設。

回答

0

哇!這種詳細的問題...

我認爲你的問題來自html5sortable插件:它使用JQuery的bind方法直接附加處理程序直接在生活元素。當這些元素在Ember控制下消失/發展時,綁定就會丟失。

該插件應該更好地使用JQuery的on方法綁定處理程序,如指定的in the documentation

+0

感謝您的閱讀,Mike!我考慮用'on'進行,但同時找到了解決方法(請參閱我的原始問題的更新)。 – sirvine 2012-04-03 06:46:02

+0

不客氣。事實上,你找到的解決方法聽起來真的很糟糕...... :-P – 2012-04-03 07:02:01

相關問題