title | section | layout |
---|---|---|
Collection Views |
view |
default |
A CollectionView is a which constructs child views by listening to membership events on a Collection. When a model is added, removed or updated in a collection, the CollectionView will add, remove or update the corresponding child view.
There are two ways to use CollectionView, programmatic and declarative. Which you use depends on the situation.
CollectionView contains the method viewForModel which can be overridden by a child class to define what view should be created when a given Model is added to the Collection. The CollectionView then takes care of inserting that View in the correct position. If the model that was used to create that View is ever removed from the Collection, the View will also be cleanly removed from the CollectionView. The example shows a simple example of this.
{% highlight javascript %} var CollectionView = require('collection_view').CollectionView; var Collection = require('collection').Collection; var Model = require('model').Model;
// Declare two models, containing a 'type' and a 'value' var model1 = new Model({type: 'url', value: 'http://facebook.com'}); var model2 = new Model({type: 'email', value: 'helpdesk@facebook.com'});
var InputCollectionView = require('javelin/core').createClass({
// Call this class InputCollectionView
name: 'InputCollectionView',
// Extend the base CollectionView class
extend: CollectionView,
members: {
// Define the viewForModel function. This should be all you need to define
// and the CollectionView class will take care of the rest
viewForModel: function(model) {
// Get the type of the model, which we set above
// This is used to decide which view we create
var type = model.get('type');
var view;
switch(type) {
case 'url':
view = this.build({
// Assume that we have some custom input for urls
view: CustomUrlInput
});
break;
case 'email':
view = this.build({
// Assume that we have some custom input for emails
view: CustomEmailInput
});
break;
}
// Bind the model to the view so that any changes to its value will
// be reflected in the view
view.setBinding(model, [{property: 'value'}]);
return view;
}
}
});
// Create an instance of our customized CollectionView var collView = new InputCollectionView();
// Insert it into the DOM collView.placeIn(document.body);
// Get the default Collection from the CollectionView. It is also possible // to pass an existing Collection to the CollectionView var coll = collView.getCollection();
// Add the two models to the Collection. This will cause two new Views to be // inserted into the InputCollectionView coll.add(model1); coll.add(model2);
{% endhighlight %}
For cases where the Collection contains different classes of Model, and each class of model can be represented by a particular type of view, a more simple declarative method of using a CollectionView is possible.
Rather than subclassing a CollectionView and overriding the viewForModel method, pass in a JSON hash called modelViewMapping defining the mapping from the declared class of a Model to the type of view to create. Using this approach, the earlier example can be changed to the code below.
{% highlight javascript %} var CollectionView = require('collection_view').CollectionView; var Collection = require('collection').Collection; var Model = require('model').Model;
// Declare two models, both containing'value' // Assume that we have two models, UrlModel and EmailModel, // both which extend Model var model1 = new UrlModel({value: 'http://facebook.com'}); var model2 = new EmailModel({value: 'helpdesk@facebook.com'});
// Create an instance of our customized CollectionView var collView = new CollectionView({ modelViewMapping: { 'UrlModel': { // Create a 'CustomUrlInput' view when a UrlModel is encountered view: 'CustomUrlInput',
// Bind the model to the view so that any changes to its value will
// be reflected in the view
bindingConfig: [{property: 'value'}]
},
'EmailModel': {
// Create a 'CustomEmailInput' view when an EmailModel is encountered
view: 'CustomEmailInput',
// Bind the model to the view so that any changes to its value will
// be reflected in the view
bindingConfig: [{property: 'value'}]
}
}
});
// Insert it into the DOM collView.placeIn(document.body);
// Get the default Collection from the CollectionView. It is also possible // to pass an existing Collection to the CollectionView var coll = collView.getCollection();
// Add the two models to the Collection. This will cause two new Views to be // inserted into the InputCollectionView coll.add(model1); coll.add(model2);
{% endhighlight %}
Deciding which approach to use depends on the situation. If all the Models in the Collection are of the same type, and deciding which view to create, and how to create it depends on some custom logic, then use the programmatic approach. If the Models in your Collection are of different classes, and there is a simple one-to-one mapping between the Model class and the type of View to create, then the declarative approach is more suitable