【问题标题】:Backbone: Assign different collection to viewBackbone:将不同的集合分配给视图
【发布时间】:2013-04-23 04:59:43
【问题描述】:

在 Backbone(实际上是 Marionette)中初始化视图后,是否可以更改其集合?我使用带有附加子项的(主)项列表的嵌套模型。该视图显示所有主要项目,并且根据这些项目的当前选择,子项目视图会发生变化。我看到的唯一选择是在选择更改后使用所选主项的子项重新创建子项视图。

这是模型:

model = [
  {
    foo: 'blah',
    bar: [{a: 1, b: 2, c: '3'}, {a: 4, b: 5, c: null}]
  },
  {
    foo: 'abcd',
    bar: [{a: 6, b: 7, c: '8'}, {a: 9, b: 10, c: '11'}]
  }
]

视图有两个并排的表:

Table1      Table2
------      ------
 blah        a=6, b=7, c='8'
*abcd        a=9, b=10, c='11'

* 表示当前选择的主要项目。我可以在选择后检索 table1 中所选主项的索引,但是如何重新初始化 table2 中的视图?

编辑: 这里有一些代码可以进一步说明:

var MainCollectionViewRow = Backbone.Marionette.ItemView.extend({
    template: _.template(...),
    tagName: 'tr'
});

var MainCollectionView = Backbone.Marionette.CompositeView.extend({
    tagName: 'table',
    template: _.template(...),
    itemView: MainCollectionViewRow,
    events: {
        'click tbody tr': 'selectItem',
    },
    appendHtml: function(collectionView, itemView, index) {
        $(itemView.el).data('index', index);
        collectionView.$('tbody').append(itemView.el);
    },
    selectItem: function(e) {
        var index = $(e.currentTarget).data('index');
        var newMainItem = this.collection.at(index);
        // This doesn't work...
        subView.initialize({'collection': newMainItem.get('bar')});
    }
});

var Bar = Backbone.Model.extend({
    defaults: {
        a: null,
        b: 0,
        c: 'text',
    }
});

var BarCollection = Backbone.Collection.extend({
    model: Bar
});

var Main = Backbone.Model.extend({ 
    defaults: {
        foo: null, 
        bar: BarCollection,
    },
    initialize: function() {
        var bar = new BarCollection(this.get('bar'));
        this.set('bar', bar);
    }
});

var MainCollection = Backbone.Collection.extend({
    model: Main,
    url: '/some/url/'
});

app.someRoute = function() {
    var region = new MainRegion();
    var layout = new MainLayout();
    region.show(layout);

    new MainCollection().fetch({
        success:function (list) {
            mainView = new MainCollectionView({
                collection: list
            });
            var subItem = list.first();
            subView = new SubCollectionView({
                collection: list.get('bar')
            });

            layout.main.show(mainView);
            layout.sub.show(subView);
        }
    });
}

app.route('some/route', 'someRoute');

【问题讨论】:

  • 是的,这是可能的。您能否发布您的视图和收藏,以便我们了解您的设置?
  • 我不认为我做了什么特别的事情。以上够吗?

标签: backbone.js marionette backbone-views backbone.js-collections


【解决方案1】:

我推荐使用 Marionette 的控制器。它需要更多代码,但随着您的应用程序的增长,您将能够保持您的集合和视图逻辑干净。您还将获得可添加书签的链接以及使用后退和前进浏览器操作。

var Router = Marionette.AppRouter.extend({
    appRoutes: {
        "": "navigate",
        "section/:index": "navigate"
    },
});

var Controller = Marionette.Controller.extend({

    initialize: function(options){
        this.region = new MainRegion();
        this.layout = new MainLayout();

        this.mainCollection = new MainCollection();
        this.subCollection = new Backbone.Collection();

        this.mainView = new MainCollectionView({
            collection: this.mainCollection
        });
        this.subView = new SubCollectionView({
            collection: this.subCollection
        });
    },
    navigate: function(index){
        index = index || 1;
        var subList = this.mainCollection.at(index);
        this.subView.collection.reset(subList);
    },
    start: function(){
        var self = this;
        var p = this.mainCollection.fetch();

        p.done(function(){
            self.showRegion();
            self.showLayout();
        })
    },
    showRegion: function() {
        this.region.show(this.layout);
    },
    showLayout: function() {
        this.layout.main.show(this.mainView);
        this.layout.sub.show(this.subView);
    }

});

Mod.addInitializer(function(){
    Mod.controller = new Controller();
    Mod.router = new Router({
        controller: Mod.controller
    });
    Mod.controller.start();
});

MainCollectionView:我们现在可以依靠路由来处理这个问题,更新您的视图以使用链接。

//selectItem: function(e) {
  //var index = $(e.currentTarget).data('index');
  //var newMainItem = this.collection.at(index);
  // reset the collection http://backbonejs.org/#Collection-reset
  //subView.collection.reset(newMainItem.get('bar'));
//}

子集合视图:

initialize: function() {
  _.bindAll(this);
  this.collection.on("reset", this.render, this);
}

【讨论】:

  • 这仅部分有效。由于 subView 的初始集合是对实际数据结构的引用,collection.reset() 将删除所有元素并添加在 reset() 调用中传递的元素,效果是模型的索引 0 和索引 1 现在重复了。是否可以设置集合的参考?如果这不可能,我必须重新创建视图...
  • 您正试图在视图中保存应用程序状态(完整集合 + 过滤结果)。由于主干非常灵活,您可以这样做,但这不是一个好主意。您的路由器/控制器应该引用完整的未过滤列表。如果您在那里处理您的 selectItem 事件,您可以从原始集合创建一个新的 filteredCollection ,使用它来重置 subView 集合。如果您可以分享您的控制器代码,我将提供一个示例。
  • 好的,我用模型定义和路由器回调更新了帖子。理想情况下,我想对原始集合进行操作,因为我打算从中添加/删除项目(即从 Bar 添加/删除项目)。
  • @Orange 更新了我的答案。
  • 谢谢斯科特。虽然我将来会考虑将应用程序移至 Marionette,但我最终使用了 these 行中的一些东西(见小提琴)。
猜你喜欢
  • 2012-11-21
  • 2023-03-31
  • 2017-03-05
  • 1970-01-01
  • 2014-02-04
  • 2013-07-11
  • 1970-01-01
  • 2013-04-06
  • 2019-12-31
相关资源
最近更新 更多