2012-03-10 12 views
2

私は以下の問題を抱えています:Backbone.js:単一のビューのみの選択を処理する方法は?

私は、目に見えて選択されているかどうかを定義するプロパティを持つモデルを持っています。このモデルは、この質問の目的でSelectModelを呼び出します。

SelectModel = Backbone.Model.extend({ 
defaults:{ 
isSelected: false 
} 
}) 

私が実際には得られない最初の部分は、どのようにして一般的な選択を処理するかです。 オブザーバーパターンを使用する場合、ビューはisSelectedプロパティーの変更をリッスンする必要があります。しかし、私の考えはまた、これを最初に引き起こすので、私は持っています。

SelectView = Backbone.View.extend({ 
initialize: function(){ 
this.model.bind("change:isSelected", this.toggleSelectionVisually) 
}, 

events: { 
"click" : toggleSelection 
}, 

toggleSelection: function(){ 
this.model.set({"isSelected": !this.model.get("isSelected"); 
}, 

toggleSelectionVisually:(){ 
//some code that shows that the view is now selected 
}, 
}) 

だから、これはそれ自体がすでにビット不条理に感じているが、私はちょうど何かを間違って理解して推測します。

私のコードを恐ろしくすることなく実際に実装できない部分は、一度に1つのモデルしか選択されていない複数のモデルの選択を処理することです。

SelectListView = Backbone.View.extend({ 
initialize: function(){ 
this.collection = new SelectList(); 
}, 

toggleSelection: function(){ 
???? 
} 
}) 

誰に選択の変更を通知する必要がありますか?どの部分がそれを引き起こし、どの部分が耳を傾けるべきか?私は本当にこれに固執しています。単一のビューのために、それは実行可能です、コレクションのために私は悲しいことに失われます。

答えて

3

私はあなたの質問の後半部分を見てまで、私はあなたのSelectViewため、次の簡素化を提案しているだろう:

SelectView = Backbone.View.extend({ 
    events: { 
    "click" : toggleSelection 
    }, 

    toggleSelection: function(){ 
    this.model.set({"isSelected": !this.model.get("isSelected"); 
    //some code that shows whether the view is selected or not 
    } 
}); 

しかし、isSelected属性は相互に排他的であるため、別の属性が切り替えられたときに暗黙的に切り替えることができます。

したがって、既存のSelectViewとを使用して、SelectListViewを次のようにすることができます。 警告:モデルが選択されるたびに、モデルのコレクション全体を反復処理します。モデルの数が多い場合、スケールがうまくいかず、コレクション全体を反復するのではなく、以前選択したモデルをキャッシュしたいと思うでしょう。

SelectListView = Backbone.View.extend({ 
    initialize: function(){ 
    this.collection = new SelectList(); 
    this.collection.bind('change:isSelected', this.toggleSelection, this); 
    }, 

    toggleSelection: function(toggledModel){ 
    //A model was toggled (on or off) 
    if(toggledModel.get('isSelected') { 
     //A model was toggled ON, so check if a different model is already selected 
     var otherSelectedModel = this.collection.find(function(model) { 
     return toggledModel !== model && model.get('isSelected'); 
     }); 

     if(otherSelectedModel != null) { 
     //Another model was selected, so toggle it to off 
     otherSelectedModel.set({'isSelected': false}); 
     } 
    } 
    } 
}); 
+0

おかげで、私は前の選択のキャッシュと一緒にこの1一番好き。 – Daniel

0

違う方法があります。コレクション自体に対してイベントをトリガーし、すべてのSelectModelインスタンスがそれをリッスンし、それに応じて更新するようにすることができます。それらのほとんどがどんな仕事をしても終わらないので、あなたがコレクションに多くのSelectModelインスタンスを持っているなら、それは少し無駄に思えます。私はおそらく、どうなることはあなたのビューで最後SelectModelを追跡するのである。

SelectListView = Backbone.View.extend({ 
    initialize: function(){ 
    this.collection = new SelectList(); 
    this.lastSelectedModel = null; 
    }, 

    toggleSelection: function(){ 
    // populate newSelectedModel with the SelectedModel that you're toggling 
    var newSelectedModel = getNewSelectedModel(); 

    if (!newSelectedModel.get('isSelected')) { 
     // if the SelectModel isn't already selected, we're about to toggle it On 
     // so we need to notify the previously selected SelectModel 
     if (this.lastSelectedModel) { 
     this.lastSelectedModel.set({isSelected: false}); 
     } 
     this.lastSelectedModel = newSelectedModel; 
    } else { 
     // if the newSelectedModel we're about to toggle WAS already selected that means 
     // nothing is selected now so clear out the lastSelectedModel 
     this.lastSelectedModel = null; 
    } 
    newSelectedModel.set({isSelected: !newSelectedModel.get('isSelected')}); 
    } 
}) 
3

お使いのモデルではなく、このビューを追跡することをお勧めします。

私の考えでは、モデルは表示とは関係なく、追跡しているデータです。ビューは、データがどこにどのように表示されるかに関するすべての情報をユーザーにカプセル化する必要があります。

したがって、isSelectedをビューの属性として指定します。次に、可視性を切り替える方法を書くのは簡単です。あなたは、特定のビューが選択されていることを他のビューを説明する必要がある場合は、あなたとあなたのtoggle_visibility方法でトリガすることができリスナー$(this.el).on('other_visible', toggle_show)を添付することができます​​

+0

私はあなたが正しいと思います。残念ながら、あなたの提案を使用するために書き直さなければならない量は、この時点でかなり大きいです。 – Daniel

+0

ああ、リファクタリングの謎。私は、オーディオプレーヤーがどのように私たちの意見に引き継がれたかを変えるためにサイトの60%を書き直さなければなりませんでした。それはとても激しく爆破した。私はあなたと一緒です。 – tkone

2
非常@rrrによって提案された解に近いが、からロジックを移動

私はそれがベローズ考えるCollectionからView

SelectsCollection = Backbone.Collection.extend({ 
    initialize: function() { 
    this.on("change:selected", this.changeSelected); 
    }, 

    changeSelected: function(model, val, opts){ 
    if(val){ 
     this.each(function(e){ 
     if(e != model && e.get("selected")) e.set("selected", false); 
     }); 
    }; 
    }, 
}); 
関連する問題