2012-04-03 71 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

相关问题