0

I have a CompositeView which is a select box that outputs options as childViews, I want to be able to only output options who's model attribute viewable is true but I'm not sure how to achieve this on each generated element. I could move the option inside of the template then wrap it in a conditional but then there would be a generated div which would break the semantics of the select. Can anyone advise on how I should approach this?

JS

var people = [{
    id: 1,
    name: 'Kyle',
    viewable: true
}, {
    id: 2,
    name: 'Peter',
    viewable: false
}, {
    id: 3,
    name: 'Simon',
    viewable: true
}];

// Create a Person Model
var Person = Backbone.Model.extend({});

// Create a People Collection
var People = Backbone.Collection.extend({
    model: Person
});

// Create a TableRowView -> ItemView
var Row = Marionette.ItemView.extend({
    template: '#row',
    tagName: 'option'
});

// Create a TableView -> CompositeView
var Overall = Marionette.CompositeView.extend({
    template: '#overall',
    childView: Row,
    childViewContainer: '.js-list',
    events: {
        'click .js-switch': 'onSwitchClick'
    },
    templateHelpers: function() {
        return {
            viewable: this.isViewable
        }
    },

    initialize: function() {
        console.log(this.collection.toJSON());

        this.isViewable = this.collection.filter(function(model){ 
            return model.attributes.viewable === true; 
        });

        console.log(this.isViewable);
    },

    onSwitchClick: function(event) {
        event.preventDefault();

        // Show all Only tem
        this.$('.js-list').select2();
    }
});

var region = new Backbone.Marionette.Region({ 
    el: '#region'
});

// Setup
var newPeople = new People(people);

var overall = new Overall({
    collection: newPeople
});

region.show(overall);

Templates

<script type="text/html" id="overall">
    <h2>Heading</h2>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.Esse iste recusandae quisquam voluptas dolorum, fugiat quaerat, dicta eum cupiditate rerum quas expedita quasi officiis quia harum quo, laborum vel debitis.. </p>


    <select class="js-list"></select>

    <button class="js-switch">Switch</button>
</script>
<script type="text/html" id="row">
    <%- name %>
</script>

Fiddle http://jsfiddle.net/99tay04x/2/

styler
  • 15,779
  • 23
  • 81
  • 135
  • Do you want the ones with `viewable: false` to also be on the HTML or not? – tegon Nov 03 '15 at 17:14
  • Initially just the ones that have viewable:true, my intention then is to show all models when you click the js-switch button – styler Nov 03 '15 at 17:14

1 Answers1

1

Collection.filter to the resque.

Just add filter to your Overall CompositeView:

filter: function (child) {
    return child.get('viewable')
}

Here's the updated example which uses filter: http://jsfiddle.net/yuraji/hkdmz4oq/

And this is a simplified working example:

var people = [{
    name: 'Kyle', viewable: true
}, {
    name: 'Peter', viewable: false
}, {
    name: 'Simon', viewable: true
}];

var Person = Backbone.Model.extend();

var People = Backbone.Collection.extend({
  model: Person
});

var PersonView = Mn.ItemView.extend({
  render: function(){
    this.$el.html( this.model.get('name') );
    return this;
  }
});

var PeopleView = Mn.CollectionView.extend({
  childView: PersonView,
  /**
    `filter` method is available in a CollectionView,
    as well as in a CompositeView, which extends from CollectionView
  */
  filter: function(child, index, collection){
    return child.get('viewable');
  }
});

var peopleView = new PeopleView({
  collection: new People(people)
});
peopleView.render().$el.appendTo(document.body);
body * {
  border: 1px solid gray;
  margin: 2px;
}
<script src='http://code.jquery.com/jquery.js'></script>
<script src='http://underscorejs.org/underscore.js'></script>
<script src='http://backbonejs.org/backbone.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/backbone.marionette/2.4.3/backbone.marionette.js'></script>
Yura
  • 2,690
  • 26
  • 32
  • Do I need to then call this filter method in some way? – styler Nov 03 '15 at 17:24
  • No, but you will need to make `render` be called on the CompositeView if the `viewable` key changes anywhere in a model. I've added example jsfiddle. – Yura Nov 03 '15 at 17:28
  • This demo seems to show all the models? Not just the ones with a true viewable property? – styler Nov 03 '15 at 17:31
  • Not really, they are made visible after 5 sec. So after 5 secs all are made visible. – Yura Nov 03 '15 at 17:32
  • I have updated the jsfiddle to clear the confusion, it just doesn't show the filtered results now. – Yura Nov 03 '15 at 17:38
  • Ah this is very helpful, so what if I wanted to show only the viewable:true entries but then clicking js-switch wanted to show every collection model? I was trying something like `this.filter = null;` http://jsfiddle.net/99tay04x/6/ – styler Nov 03 '15 at 18:56
  • 1
    I have updated the jsfiddle again to show how you can do that. Basically I am also checking custom `viewAll` property, which I change on button click, then the list renders with this filter logic. – Yura Nov 03 '15 at 20:06