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>
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>