Skip to content

Instantly share code, notes, and snippets.

@brianally
Last active August 29, 2015 14:24
Show Gist options
  • Save brianally/c22ec8ab4468ef09c01b to your computer and use it in GitHub Desktop.
Save brianally/c22ec8ab4468ef09c01b to your computer and use it in GitHub Desktop.
Multiple filters for Ember-Data
// some controller
import Ember from 'ember';
export default Ember.Controller.extend({
responses : [],
filteredResponses: [],
sectors : [],
dateFrom : null,
dateTo : null,
filters : {
region: {},
sector: {},
date : {}
},
minDate: function() {
// responses are sent already ordered by date so just get first in list
var responses = this.get('filteredResponses');
if ( responses.length ) {
var created = responses[0].get('respondent').get('created').toString();
return new Date(created);
}
return new Date();
}.property('responses', 'filteredResponses', 'dateFrom'),
maxDate: function() {
var responses = this.get('filteredResponses');
if ( responses.length ) {
var created = responses.get('lastObject').get('respondent').get('created').toString();
return new Date(created);
}
return new Date();
}.property('responses', 'filteredResponses', 'dateTo'),
actions: {
filterByRegion: function (fnFilter) {
this.set('filters.region', fnFilter);
this.notifyFilterChange();
},
filterBySector: function (fnFilter) {
this.set('filters.sector', fnFilter);
this.notifyFilterChange();
}
// no action for date; uses observer
},
dateDidChange: function() {
var dateFrom = this.get('dateFrom') || this.get('minDate');
var dateTo = this.get('dateTo') || this.get('maxDate');
var from = moment( new Date(dateFrom.toString()) );
var to = moment( new Date(dateTo.toString()) );
if (to.isBefore(from, 'day')) {
alert(''to' cannot come before 'from'!');
return;
}
var fnFilter = function(item) {
var created = moment( new Date(item.get('respondent').get('created').toString()) );
return (from.isBefore(created, 'day') || from.isSame(created, 'day') ) && ( created.isBefore(to, 'day') || created.isSame(to, 'day') );
};
this.set('filters.date', fnFilter);
this.notifyFilterChange();
}.observes('dateFrom', 'dateTo'),
notifyFilterChange: function() {
var filters = this.get('filters');
// we want the unfiltered responses because we'll iterate through all filters
var responses = this.model.get('responses');
Object.keys(filters).forEach(function(n) {
if ( typeof filters[n] === 'function' ) {
responses = responses.filter( filters[n] );
}
});
this.set('filteredResponses', responses);
}
});
// bootstrap-dropdown-select-filter.js
import Ember from 'ember';
export default Ember.Component.extend({
valueKey: 'id',
labelKey: 'name',
selectedOption: function() {
if (Ember.isEmpty(this.get('value'))) {
return {id: 0, name: 'All'};
} else {
return this.get('options').findProperty('id', this.get('value'));
}
}.property('options', 'value'),
actions: {
select: function(opt) {
this.set('value', opt.id);
var fnFilter = function(item) {
return this.get('value') === Ember.get(item, this.get('filter-key-path'));
}.bind(this);
this.sendAction('action', fnFilter);
},
reset: function() {
this.set('value', null);
this.sendAction('action', function() { return true; });
}
}
});
// region-filter.js
// see:
// http://blessanmathew.com/2014/08/16/ember.js-list-filtering-using-a-multiple-selection-filter-component.html
import Ember from 'ember';
export default Ember.Component.extend({
selectedItems: [],
click: function(event) {
var el = Ember.$(event.target);
var filterFn;
if (el.is('input[type=checkbox]')) {
if (el.is(':checked')) {
this.get('selectedItems').pushObject(el.val());
} else {
this.get('selectedItems').removeObject(el.val());
}
}
if (this.get('selectedItems.length')) {
filterFn = function(item) {
return this.get('selectedItems')
.contains(Ember.get(item, this.get('filter-key-path')));
}.bind(this);
} else {
filterFn = function() {return true;};
}
this.sendAction('action', filterFn);
}
});
// multiple-selection-filter.js
// see:
// http://blessanmathew.com/2014/08/16/ember.js-list-filtering-using-a-multiple-selection-filter-component.html
import Ember from 'ember';
export default Ember.Component.extend({
selectedItems: [],
// for each checked checkbox, store value in selectedItems
setSlectedItems: function() {
var _this = this;
this.$('input[type=checkbox]').each(function(i, el) {
if ( _this.$(el).is(':checked') ) {
_this.get('selectedItems').pushObject( _this.$(el).val() );
}
});
}.on('didInsertElement'),
// set all checkboxes to checked state and store values
resetChecked: function() {
var _this = this;
this.$('input[type=checkbox]').each(function(i, el) {
_this.$(el).prop('checked', true);
_this.get('selectedItems').pushObject( _this.$(el).val() );
});
},
click: function(event) {
var el = this.$(event.target);
var filterFn;
if (el.is('input[type=checkbox]')) {
if (el.is(':checked')) {
this.get('selectedItems').pushObject(el.val());
} else {
this.get('selectedItems').removeObject(el.val());
}
}
if (this.get('selectedItems.length')) {
filterFn = function(item) {
return this.get('selectedItems')
.contains(Ember.get(item, this.get('filter-key-path')));
}.bind(this);
} else {
this.resetChecked();
filterFn = function() { return true;}.bind(this);
}
this.sendAction('action', filterFn);
}
});
/*
{{! single-select dropdown -- choose a sector }}
<div class="sectors">
<h5>Filter by sector</h5>
{{ui/bootstrap-dropdown-select-filter
options=sectors
filter-key-path="respondent.sector.id"
action="filterBySector"}}
</div>
{{! multi-select checkboxes -- deselect regions }}
<ul class="region-group">
<h5>Filter by region</h5>
{{#ui/multiple-selection-filter filter-key-path="respondent.region.name" action="filterByRegion"}}
{{#each region in regions}}
<li class="">
<label>
<input type="checkbox" class="item-checkbox" {{bind-attr value=region}} checked="checked" />
{{region}}
</label>
</li>
{{/each}}
{{/ui/multiple-selection-filter}}
</ul>
{{! dual datepickers -- narrow date interval }}
<div class="date-range form-inline">
<h5>Filter by date</h5>
<div class="form-group">
<label>From:</label>
{{bootstrap-datepicker
value=dateFrom
startDate=minDate
endDate=maxDate
format="yyyy-mm-dd"
autoClose=true
clearBtn=true}}
</div>
<div class="form-group">
<label>To:</label>
{{bootstrap-datepicker
value=dateTo
startDate=minDate
endDate=maxDate
format="yyyy-mm-dd"
autoClose=true
clearBtn=true}}
</div>
</div>
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment