2014-10-03 22 views
2

我有一個項目的集合。我想跟蹤當前的選擇。當用戶點擊集合中的其他項目時,我想指出該項目已被選中並顯示所選項目的詳細信息。把它想象成一個具有詳細視圖的列表(就像典型的電子郵件客戶端一樣)。主從佈局如何組織具有特定選擇的Backbone集合?

例(source): Example of a master-detail layout

我現在有這樣的事情(寫在CoffeeScript中,模板使用haml-coffee):

class Collections.Items extends Backbone.Collection 
    model: Models.Item 

    setCurrentSelection: (id)-> 
    # what to do here? Is this even the right way to do it? 

    getCurrentSelection: -> 
    # what to do here? Is this even the right way to do it? 

class Views.ItemsPage extends Backbone.View 

    list_template: JST['items/list'] 
    details_template: JST['items/details'] 

    events: 
    'click .item': 'updateSelection' 

    initialize: (options)-> 
    @collection = options.collection 

    render: -> 
    $('#items_list').html(@list_template(collection: @collection.toJSON())) # not sure if this is how to render a collection 
    $('#item_details').html(@details_template(item: @collection.currentSelection().toJSON())) # how to implement currentSelection? 
    @ 

    updateSelection: (event)-> 
    event.preventDefault() 
    item_id = $(event.currentTarget).data('id') 
    # mark the item as selected 
    # re-render using the new selection 

# templates/items/list.hamlc 
%ul 
    - for item in @collection 
    %li{data:{id: item.id}, class: ('selected' if item.selected?)} # TODO: How to check if selected? 
     = item.name 

# templates/items/details.hamlc 
%h2= @item.name 
+0

你使用任何模板引擎?你能發佈你的html代碼嗎? – srinivasan 2014-10-03 07:44:17

+0

我添加了一個模板的例子......它主要是僞代碼,所以我不確定它們是否有效 – Andrew 2014-10-03 17:30:38

回答

1

我不知道,如果我跟着你(我的CoffeeScript有點生疏),但我認爲你要做的是在updateSelection方法的適當模型上設置一個selected屬性,然後重新渲染你的視圖。

換句話說:

updateSelection: (event)-> 
    event.preventDefault() 
    item_id = $(event.currentTarget).data('id') 
    model = this.collection.get(item_id) # get the model to select 
    model.selected = true # mark the item as selected 
    this.render() # re-render using the new selection 
+0

這是否設置全局模型的屬性?例如,如果我再次用'this.collection.get(item_id)'獲取它,模型是否仍然具有'selected'屬性?但更重要的問題是「這是做到這一點的正確方法嗎?」還是有一種更好,更乾淨的方式按照它的意圖使用Backbone? – Andrew 2014-10-06 23:18:16

+0

它不;如果你希望數據持久存在,你應該使用一個*屬性*(例如'model.set('selected',true);'),然後在某個時間點保存模型。至於「正確的方式」,只要你有想要在Backbone中的服務器上保存的數據,保存它的正確方法是將其保存爲「Model」屬性(所以是的,這是正確的方式)。如果這只是暫時的選擇而不能保留,那麼一個財產(如我原先所建議的)將是更好的方式。 – machineghost 2014-10-06 23:33:19

+0

對不起,我的意思是說「選擇」只是一個客戶端狀態。它不需要保留在服務器端,而是通過Backbone路由。我的意思是可能有更好的方法來跟蹤我沒有想到的狀態。 – Andrew 2014-10-07 05:44:39

1

甚至說:「我的CoffeeScript是有點生鏽」是我太重要了。但我仍會盡力在js中儘可能地解釋。

首先,骨幹的方式是保持模型作爲REST資源文檔的表示。 (服務器端 - 持久數據)。

客戶端呈現邏輯應堅持觀點。要記住哪個列表項在細節部分中可見,是該特定視圖的作業。啓動對細節的更改請求視圖模型是項目列表的作業。

理想的方法是對列表和細節有兩個單獨的視圖。 (你也可以去多一點進取,有在列表視圖中的每個項目的視圖。

父視圖

var PageView = Backbone.View.extend({ 
     initialize: function() { 
      //initialize child views 
      this.list = new ItemListView({ 
       collection : this.collection //pass the collection to the list view 
      }); 
      this.details = new ItemDetailView({ 
       model : this.collection.at(1) //pass the first model for initial view 
      }); 

      //handle selection change from list view and replace details view 
      this.list.on('itemSelect', function(selectedModel) { 
       this.details.remove(); 
       this.details = new ItemDetailView({ 
        model : selectedModel 
       }); 
       this.renderDetails(); 
      }); 
     }, 

     render: function() { 
      this.$el.html(this.template); // or this.$el.empty() if you have no template 
      this.renderList(); 
      this.renderDetails(); 
     }, 

     renderList : function(){ 
      this.$('#items_list').append(this.list.$el); //or any other jquery way to insert 
      this.list.render(); 
     }, 

     renderDetails : function(){ 
      this.$('#item_details').append(this.details.$el); //or any other jquery way to insert 
      this.details.render(); 
     } 
    }); 

列表視圖

var ItemListView = Backbone.View.extend({ 
    events : { 
     'click .item': 'updateSelection' 
    }, 
    render: function() { 
     this.$el.html(this.template); 
     this.delegateEvents(); //this is important 
    } 
    updateSelection : function(){ 
     var selectedModel; 
     // a mechanism to get the selected model here - can be same as yours with getting id from data attribute 
     // or you can have a child view setup for each model in the collection. which will trigger an event on click. 
     // such event will be first captured by the collection view and thn retriggerd for page view to listen. 
     this.trigger('itemSelect', selectedModel); 
    } 
}); 

詳細信息視圖

var ItemDetailView = Backbone.View.extend({ 
    render: function() { 
     this.$el.html(this.template); 
     this.delegateEvents(); //this is important 
    } 
}); 

如果您不重用您的視圖,這將不會通過路線持續狀態。在這種情況下,你需要有一個全局的狀態/事件保存機制。財產以後像以下 -

window.AppState = {}; 
_.extend(window.AppState, Backbone.Events); 

//now your PageView initilize method becomes something like this - 
initialize: function() { 
    //initialize child views 
    this.list = new ItemListView({ 
     collection : this.collection //pass the collection to the list view 
    }); 
    var firstModel; 
    if(window.AppState.SelectedModelId) { 
     firstModel = this.collection.get(window.AppState.SelectedModelId); 
    } else { 
     firstModel = this.collection.at(1); 
    } 
    this.details = new ItemDetailView({ 
     model : firstModel //pass the first model for initial view 
    }); 

    //handle selection change from list view and replace details view 
    this.list.on('itemSelect', function(selectedModel) { 
     window.AppState.SelectedModelId = selectedModel.id; 
     this.details.remove(); 
     this.details = new ItemDetailView({ 
      model : selectedModel 
     }); 
     this.renderDetails(); 
    }); 
} 

EDIT
處理在列表視圖中選擇的類(突出顯示)。請參閱評論以供參考。

列表視圖模板 -

<ul> 
    <% _.each(collection, function(item, index){ %> 
    <li data-id='<%= item.id %>'><%= item.name %></li> 
    <% }); %> 
</ul> 

內部列表視圖中添加下面的方法 -

changeSelectedHighlight : function(id){ 
    this.$(li).removeClass('selected'); 
    this.$("[data-id='" + id + "']").addClass('selected'); 
} 

只需調用從updateSelection方法和瀏覽量期間初始化此方法。

this.list.changeSelectedHighlight(firstModel.id); 
+0

我喜歡這裏要去的地方。你能否詳細說明'delegateEvents()'的目的以及爲什麼它很重要? – Andrew 2014-10-07 18:44:58

+0

通過使用新模型設置'model'屬性重用ItemDetailView'然後重新渲染是不是一個好主意?或者是更好地刪除,創建一個新的實例,並呈現新的實例? – Andrew 2014-10-07 18:48:22

+0

最後一個問題:將一個「selected」類添加到該項目時,模板會是什麼樣子? – Andrew 2014-10-07 19:46:27