Marionette.js CollectionView, only render specific models
Asked Answered
S

4

6

I am refactoring my Backbone.js application to use Marionette.js, and I am trying to wrap my head around a CollectionView.

Suppose I have several ItemViews with the model Cow:

// Declare my models.
var Cow = Backbone.Model.extend({});
var Cows = Backbone.Collection.extend({
  model: Cow
});

// Make my views
var GrassPatch = Marionette.ItemView.extend({
  tagName:  'div',
  template: "<section class='grass'>{{name}}</section>",
})

var Pasture = Marionette.CollectionView.extend({});

// Instantiate the CollectionView,
var blissLand = new Pasture({
  itemView: GrassPatch;
});

// Now, add models to the collection.
Cows.add({
  name: 'Bessie',
  hasSpots: true
});

Cows.add({
  name: 'Frank',
  hasSpots: false
});

Now here's the trick. I only want cows with spots in my pasture. How, in defining my CollectionView (Pasture), do I tell it to only pay attention to those models whose hasSpots === true?

Ideally I would like to have the CollectionView filter that in all events, but minimally, how do I only render some ItemViews based on their model properties?

UPDATE

I used David Sulc's examples and this worked out to an easy solution. Here's an example implementation:

  this.collection = Backbone.filterCollection(this.collection, function(criterion){
    var len = String(criterion).length;
    var a = criterion.toLowerCase();
    return function(model){
      var b = String(model.get('name')).substr(0, len).toLowerCase();
      if (a === b) {
        return model;
      }
    };
  });

  this.collection.add({ name: 'foo' });
  this.collection.add({ name: 'foosball' });
  this.collection.add({ name: 'foo bar' });
  this.collection.add({ name: 'goats' });
  this.collection.add({ name: 'cows' });

  this.collection.filter('foo');

  // -> returns the first three models
Schofield answered 4/9, 2013 at 1:50 Comment(1)
I would control this at the collection level: #11762605Lyre
D
0

As suggested by others, the best way to achieve this is to filter the collection to contain only the models you want to display, and pass that fitlered collection to a CollectionView for rendering.

You can see a working example here: http://davidsulc.github.io/marionette-gentle-introduction/#contacts Filter contacts with the input field on the top right to display only models containing that text (e.g. "li").

This is achieved by using a special collection type that handles filtering: https://github.com/davidsulc/marionette-gentle-introduction/blob/master/assets/js/entities/common.js

And it gets instantiated here: https://github.com/davidsulc/marionette-gentle-introduction/blob/master/assets/js/apps/contacts/list/list_controller.js#L13

This code is from my book on Marionette.

Definite answered 4/9, 2013 at 6:38 Comment(1)
Marionette.js has a new feature for filtering a collection view: marionettejs.com/docs/v2.4.3/… See @jeff answer bellow.Tupelo
P
3

Marionette handles this for you in v2.4.1.

See the CollectionView.filter method.

Following is from the docs:

  var cv = new Marionette.CollectionView({
    childView: SomeChildView,
    emptyView: SomeEmptyView,
    collection: new Backbone.Collection([
      { value: 1 },
      { value: 2 },
      { value: 3 },
      { value: 4 }
    ]),

    // Only show views with even values
    filter: function (child, index, collection) {
      return child.get('value') % 2 === 0;
    }
  });

  // renders the views with values '2' and '4'
  cv.render();

  // change the filter
  cv.filter = function (child, index, collection) {
    return child.get('value') % 2 !== 0;
  };

  // renders the views with values '1' and '3'
  cv.render();

  // remove the filter
  // note that using `delete cv.filter` will cause the prototype's filter to be used
  // which may be undesirable
  cv.filter = null;

  // renders all views
  cv.render();
Proglottis answered 20/3, 2015 at 7:28 Comment(0)
R
0

@Will M's suggestion to filter the collection is the appropriate way to do this.

Readability answered 4/9, 2013 at 6:32 Comment(0)
D
0

As suggested by others, the best way to achieve this is to filter the collection to contain only the models you want to display, and pass that fitlered collection to a CollectionView for rendering.

You can see a working example here: http://davidsulc.github.io/marionette-gentle-introduction/#contacts Filter contacts with the input field on the top right to display only models containing that text (e.g. "li").

This is achieved by using a special collection type that handles filtering: https://github.com/davidsulc/marionette-gentle-introduction/blob/master/assets/js/entities/common.js

And it gets instantiated here: https://github.com/davidsulc/marionette-gentle-introduction/blob/master/assets/js/apps/contacts/list/list_controller.js#L13

This code is from my book on Marionette.

Definite answered 4/9, 2013 at 6:38 Comment(1)
Marionette.js has a new feature for filtering a collection view: marionettejs.com/docs/v2.4.3/… See @jeff answer bellow.Tupelo
V
0

Sometimes you can not filter your collection due to some custom logic and you want those models to be in a collection, but you don't want them to be rendered. To achieve it, you can:

var Pasture = Marionette.CollectionView.extend({
     addChild: function(child, ChildView, index) {
               if(child.get('hasSpots')) {
                    return Marionette.CollectionView.prototype.addChild.call(this, child, ChildView, index);
               }
     }});

Although I agree that filtering a collection is a much better way to do this.

Variant answered 7/10, 2014 at 12:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.