I am trying to combine sorting properties ( sortProperties
and sortAscending
) with filters on a list of data.
I have an ArrayController
and two actions, one for sorting and one for filters. Filter action sets properties on filters
object, but property that depends on filters
is not re-calucalted.
Relevant controller code:
App.PostsController = Ember.ArrayController.extend({
filters: Ember.Object.create({}),
filteredContent: function () {
var ret = this.get('arrangedContent');
Object.keys(this.filters).forEach(function (name) {
ret = ret.filter(this.filters.get(name));
}, this);
return ret;
// I expect this to cause `filteredContent` to depend on `filters` property
}.property('arrangedContent', 'filters'),
actions: {
sort: function(property, isSorted) {
this.set('sortProperties', [property]);
if (isSorted) {
this.toggleProperty('sortAscending');
} else {
this.set('sortAscending', true);
}
},
filter: function (property, value) {
var filters = this.get('filters');
switch (property) {
case 'id':
// I expect that call to `set` would trigger `filteredContent` property update
filters.get('id') || filters.set('id', function (post) {
return post.get('id') < value;
});
break;
case 'title':
filters.get('title') || filters.set('title', function (post) {
return post.get('title').indexOf(value) !== -1;
});
break;
}
}
}
});
So, my question is why filters.set()
doesn't cause filteredContent
function to run?
All code is here – http://jsbin.com/silun/7/edit?html,js,output
You are updating properties on the filters
object, so you need to observe the specific object attributes you are changing.
You can do this by explicitly listing the attributes to depend on:
filteredContent: function () {
//...
}.property('arrangedContent', 'filters.id', 'filters.title'),
or by using a shorthand notation called property brace expansion .
filteredContent: function () {
//...
}.property('arrangedContent', 'filters.{id,title}'),
Updated JSBin: http://jsbin.com/nuyegowede/1/edit
new JSBin with filters
as array: http://jsbin.com/yayihazoza/1/edit
If you want unlimited filter attributes without updating the computed property you can use a configure filters
as an array instead of an object. This lets you use Ember's array observer features ( @each to automatically update the filtering when the array changes.
filters
is now an array of filter objects that are in this form:
{
name: 'name-of-filter',
filter: function(){
// implementation of filter here
}
}
update filter
to push the filter objects into the filters
array:
filter: function (property, value) {
var filters = this.get('filters');
console.log("filter", property, value);
switch (property) {
case 'id':
if (filters.findBy('name', 'id') === undefined) {
filters.pushObject({
name: 'id',
filter: function (post) {
return (post.get('id') < value);
}
});
}
break;
case 'title':
if (filters.findBy('name', 'title') === undefined) {
filters.pushObject({
name: 'title',
filter: function (post) {
return post.get('title').indexOf(value) !== -1;
}
});
}
break;
}
}
update the computed property to use the new filter objects and also to listen for changes to each item in the array
filteredContent: function () {
var ret = this.get('arrangedContent');
var filters = this.get('filters');
filters.forEach(function (filterObj) {
ret = ret.filter(filterObj.filter);
}, this);
return ret;
}.property('arrangedContent', 'filters.@each'), // <-- notice the new @each
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.