如何组织具有特定选择的Backbone集合?

时间:2014-10-03 03:10:36

标签: backbone.js

我有一系列物品。我想跟踪当前的选择。当用户单击集合中的其他项目时,我想指示该项目已被选中并显示所选项目的详细信息。可以将其视为带有详细视图的列表(如典型的电子邮件客户端)。

主 - 详细布局示例(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

2 个答案:

答案 0 :(得分:1)

我不确定我是否关注你(我的CoffeeScript有点生疏),但我认为你要做的是在{{{{{}}的相应模型上设置selected属性1}}方法,然后重新渲染您的视图。

换句话说:

updateSelection

答案 1 :(得分: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();
    });
}

修改
在列表视图中处理选定的类(突出显示)。请参阅评论以供参考。

列表视图模板 -

<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方法调用此方法,并在PageView初始化期间调用。

this.list.changeSelectedHighlight(firstModel.id);