2
votes

After having initialised a view in Backbone (actually Marionette), is it possible to change its collection? I use a nested model of a list of (main) items with additional sub items. The view displays all main items and depending on the current selection of those items, the sub item view changes. The only option I see is to re-create the sub item views with the sub items of the selected main item once the selection changes.

Here's the model:

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

The view has two tables side-by-side:

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

The * denoting the currently selected main item. I'm able to retrieve the index of the selected main item in table1 upon selection, but how do I reinitialise the view in table2?

Edit: Here's some code for further illustration:

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');
1
Yes it is possible. Can you post your view and collection so we can see how you have things setup?Scott Puleo
I don't think I did anything special. Is the above sufficient?orange

1 Answers

1
votes

I recommend using Marionette's Controller. It is a little more code but as your app grows you will be able to keep your collection and view logic clean. You will also get bookmark-able links and the use of back and forward browser actions.

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: We can now rely on routes to handle this, update your view to use links.

//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'));
//}

SubCollectionView:

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