简体   繁体   中英

Ember controller computed property (of type Object) update doesnt work

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

Update

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM