2012-04-03 7 views
2

私はChecklistモデルを持つEmber.jsアプリを持っています。各チェックリストには多くのCheckitemsがあります。 (古典的なToDoアプリの亜種ですが、複数のTodoListsがあります)Ember.jsビューでjQueryバインディングをリフレッシュする適切な方法は何ですか?

一番上のビューでは、利用可能なすべてのチェックリストのリストが左側に表示されます。チェックリストを選択すると、対応するチェック項目が右側に表示されます。

右側のチェック項目はドラッグ可能です。私はドラッグのソートを処理するためにthis html5sortable libraryを使用しています。これは、古典的なjQueryUIのバージョンのようですが、あまりclunky。

アプリの最初の読み込み時に、ソート可能なリストは正常に機能します。ただし、チェック項目の一覧が変更された場合(チェック項目が完了とマークされているか、新しいチェック項目が追加されているか、既存のチェック項目の変更が保存されているか、左側に別のチェックリストが選択されているため)、html5sortableへのバインディングは失われます。

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}} 

そして、良い対策のため、コントローラのアプリが最初にロード、私はApp.CheckitemsPendingTableViewビューと呼ばれている

そのビューの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属性が変更されると、子ビューは現在選択されているチェック項目のリストを反映するように忠実に調整されます。しかし、sortable()への元のバインディングは失われており、jQuery経由でsortable()に再バインドするための明確なフックはありません。

CheckitemsPendingTableViewという子ビューで再バインドすることはできません。これは、現在選択されているリストのチェック項目のすべてのインスタンスで繰り返されるためです。コントローラやモデルからは再バインドできません。DOMの更新が完了する前にバインドを試みるためです。

私はこれについて間違って考えていると確信しています。私はEmber.jsを新しくしました(それがはっきりとわからない場合)。そして、このケースがどのように正しく処理されているかを理解するのに苦労しています。

UPDATE私はApp.CheckitemsPendingTableViewに次の関数と観測者を追加することによって、この問題を解決:私はthis answerに私の解決策をベース

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]') 

。実行ループの反復中にDOMが完了することを前提にしているように思われるので、それは大きな解決策ではないことを少しは心配しています。

答えて

0

Whoa!詳細な質問の種類...

あなたの問題は、html5sortableプラグインから来ていると思います.JQueryのbindメソッドを使用して、生きた要素に直接ハンドラをアタッチします。これらの要素がEmberコントロールの下で消滅/進化するにつれて、バインディングは失われます。

プラグインは、ハンドラをバインドするために、in the documentationのように、JQueryのonメソッドを使用することをお勧めします。

+0

マイクをお読みいただきありがとうございます。私は 'on'で行くと考えましたが、その間に回避策を見つけました(私の元の質問への更新を参照)。 – sirvine

+0

ようこそ。確かに、あなたが見つけた回避策は本当に泥酔しています... :-P –

関連する問題