Search code examples
aurelia

SortValueConverter not working correctly when order of an existing item is changed


I would like to list the content of my array on my view. This must be sorted. Below is my first implementation.

app.js:

export class App {

    items: Array = [
        { order: 2, color: 'Red' },
        { order: 5, color: 'Green' },
        { order: 1, color: 'Blue' },
        { order: 4, color: 'Yellow' }
    ];
    get sortedItems() {
        var elms = this.items.slice(0);
        return elms.sort(function (a, b) {
            return a.order - b.order;
        });
    }
    addElement() {
        var elm = { index: 4, order: 3, color: 'Brown' };
        this.items.push(elm);
    }
    changeElement() {
        var elm = this.items.find(x => x.color == 'Blue');
        elm.order = 7;
    }
}

app.html:

<template>  

  <ul>
    <li repeat.for="item of sortedItems">
      ${item.order} - ${item.color}
    </li>
  </ul>

  <button click.trigger='addElement()'>Add</button>
  <button click.trigger='changeElement()'>Change</button>

</template>

https://gist.run/?id=fadff61b1159fd1d4dcfaf1ed4c4990e

It works as expected.

  • At runtime, the list is sorted
  • When a new item is added in the array, it is correctly displayed (sorted) in the view
  • When the order value of an existing item is changed, it is correctly adjusted (sorted) in the view

But now I would like to use a ValueConverter for sorting my list. So below is my second implementation.

app.js:

export class App {

    items: Array = [
        { order: 2, color: 'Red' },
        { order: 5, color: 'Green' },
        { order: 1, color: 'Blue' },
        { order: 4, color: 'Yellow' }
    ];
    get allItems() {
      return this.items;
    }
    addElement() {
        var elm = { index: 4, order: 3, color: 'Brown' };
        this.items.push(elm);
    }
    changeElement() {
        var elm = this.items.find(x => x.color == 'Blue');
        elm.order = 7;
    }
}

app.html:

<template>

  <require from="./sort"></require>

  <ul>
    <li repeat.for="item of allItems | sort:'order':'ascending'">
      ${item.order} - ${item.color}
    </li>
  </ul>

  <button click.trigger='addElement()'>Add</button>
  <button click.trigger='changeElement()'>Change</button>

</template>

sort.js:

export class SortValueConverter {
  toView(array, propertyName, direction) {
    let factor = direction === "ascending" ? 1 : -1;
    return array.sort((a, b) => {
      return (a[propertyName] - b[propertyName]) * factor;
    });
  }
}

https://gist.run/?id=06f97d4b12b43c2fd3d727fb49edd1c0

With this implementation the sort is not working after changing the order of the Blue element.

  • At runtime, the list is sorted
  • When a new item is added in the array, it is correctly displayed (sorted) in the view
  • BUT when the order value of an existing item is changed, it is NOT correctly adjusted (sorted) in the view

How can I proceed to have my array correctly sorting elements when value of an existing item is changed.


Solution

  • you can use a signal on the binding, and whenever you mutate an item in the array - emit a signal and the binding will kick in again.