Harshal Pandya
Harshal Pandya

Reputation: 1624

Render view on click event

Is there a way so that the ItemViews contained in a CompositeView only render on say clicking a button? I would like a change in the collection to update the Composite View's dom but each individual ItemView should not render until required.

Pardon me if I'm a little vague in my description but I have very limited knowledge of backbone and marionette.

Upvotes: 0

Views: 543

Answers (1)

seebiscuit
seebiscuit

Reputation: 5053

As you well know, Marionette is eager to take your Composite (or Collection) View's children views and spawn them. That's why included in the Composite View render method is the _renderChildren process. Once invoked, there's really no way to selectively render children views.

But there's a back door that gets around rendering your entire collection. It's a simple as initializing your Composite View with an empty collection, like this

//Define MyCollection` and MyCompositieView and then...
var myCollection = new MyCollection(); // Construct an empty collection

var myCompositeView = new MyCompositeView({ collection: myCollection });

An "empty" Composite View will render its own template normally, and simply skip _renderChildren.

You can then wire an event to call myCompositeView.collection.add(model). You'll notice that Marionette listens for an add event on your collection,

_initialEvents: function() {
  if (this.collection) {
    this.listenTo(this.collection, 'add', this._onCollectionAdd);

    // Other _initialEvents methods...
  }
},

and _onCollectionAdd is responsible for rendering the added model:

_onCollectionAdd: function(child) {
  this.destroyEmptyView();
  var ChildView = this.getChildView(child);
  var index = this.collection.indexOf(child);
  this.addChild(child, ChildView, index);  // The rendering happens here
},

Putting it all together

To make this work you'd have to have an array of your models inside your CompositeView, but outside that view's collection. I usually just wire up an $.getJSON (or any other AJAX method) to get the data and store it in a property of the View object. Say you do this on initialize:

initialize: function() {
  var that = this,
      dataUrl = "some/url";
  $.getJSON(dataUrl, function(data) {
    that.myModels = data;
  });
},

And, in your Composite View you'd probably have an event, say a click on an element of your Composite view:

events: {
  'click button': 'addChild'
}

addChild: function (event) {
  // functionality to identify which child to add to the collection
  this.collection.add(this.myModels[j]); // Where 'j' is the index the model you want lives in.
});

When addChild is called the collection adds the proper model, and Mariontte makes sure to render a child view populated with this model.

There variations on how to do this, and you don't have to have an event wired in your view. But I think I proved how you can have methods render independently. If you provide more information I can give you more ideas.

Upvotes: 2

Related Questions