Search code examples
ember.jscomputed-properties

How to use a filtered computed property with ember-drag-drop sortable-objects?


I'm using ember-drag-drop to implement a sortable list. This worked fine until I needed to implement a text filter on the list.

{{#sortable-objects sortableObjectList=filteredItems enableSort=true}}
  {{#each filteredItems as |item index|}}
    {{#draggable-object content=item isSortable=true isDraggable=true}}
      {{item.name}}
    {{/draggable-object}}
  {{/each}}
{{/sortable-objects}}

The filteredItems is a computed property which filters the original list based on a user's text input.

filteredItems: computed('items', 'term', function() {
  let term = this.get('term');
  let items = this.get('items');

  if (term.length > 0) {
    return items.filter(item => item.conditions.some(cond => cond.field.toLowerCase().indexOf(term) > -1 || (cond.term && cond.term.toLowerCase().indexOf(term) > -1)));
  } else {
    return items;
  }
}),

The problem is that a computed can't (normally) be written back to. The actual drag and drop works (the items appear in a different order in the browser), however, the data original order of the items doesn't change.

How can I still allow sorting of the original items data set while still allowing filtering?


Solution

  • Ember's computed properties can also be setted. In your case, you need to define your computed by enabling the set function (from this working twiddle) like this:

    filteredItems: Ember.computed('items', 'term', {
        get(key) {
          let term = this.get('term');
          let items = this.get('items');
    
          if (term && term.length > 0) {
            let filteredItems = items.filter(item => item.name.indexOf(term) > -1);
            return filteredItems;
          } else {
            return items;
          }
        }, 
        set(key, value) {
          let items = this.get('items');
          let filteredItemsCount = 0;
          let newItems = Ember.makeArray();
          items.forEach(function(item, index){
            if(value){
              if(value && value.indexOf(item) > -1){
                 newItems[index] = value[filteredItemsCount];
                 filteredItemsCount++;
              }
              else{
                newItems[index] = items[index];
              }
            }
            else{
                newItems[index] = items[index];
            }
          });
    
          this.set('items', newItems);
    
          return value;
        }
    })