angular keyvalue pipe sort properties / iterate in

2019-02-25 18:19发布

When using the Angular keyvalue pipe to iterate over an object's properties as follows:

<div *ngFor="let item of object | keyvalue">
  {{item.key}}:{{item.value}}
</div>

I have experienced an issue where the properties were not iterated in the order expected. And this comment suggests that I am not the only one to experience this issue:

How to loop over object properties with ngFor in Angular

Can someone advise what determines the order of iteration when using the keyvalue pipe please and how to force a specific iteration order? My ideal order of iteration is the order in which the properties were added.

Thanks

3条回答
神经病院院长
2楼-- · 2019-02-25 18:51

This is same as accepted answer, but it has more complex object so It can help somebody How to sort by custom index field and using keyval pipe.

In angular component:

myObject = {
    "key1": { val:"whateverVal1", code:"whateverCode1", index: 1},
    "key2": { val:"whateverVal2", code:"whateverCode2", index: 0},
    "key3": { val:"whateverVal3", code:"whateverCode3", index: 2}
}

Sorting function in component:

indexOrderAsc = (akv: KeyValue<number, any>, bkv: KeyValue<number, any>): number => {
        const a = akv.value.index;
        const b = bkv.value.index;

        return a > b ? 1 : (b > a ? -1 : 0);
    };

in template:

<div *ngFor="let x of myObject | keyvalue:indexOrderAsc">
    ...
</div>
查看更多
Luminary・发光体
3楼-- · 2019-02-25 18:52

According to the Angular documentation, the keyvalue pipe sorts the items by key order by default. You can provide a comparer function to change the sort order, but it only considers the key and value properties, not the entry order.

For example, the following comparer functions sort the items by increasing value order, and by reverse key order, respectively:

valueAscOrder = (a: KeyValue<number,string>, b: KeyValue<number,string>): number => {
  return a.value.localeCompare(b.value);
}

keyDescOrder = (a: KeyValue<number,string>, b: KeyValue<number,string>): number => {
  return a.key > b.key ? -1 : (b.key > a.key ? 1 : 0);
}

when applied to the keyvalue pipe:

<div *ngFor="let item of object | keyvalue: valueAscOrder">
  {{item.key}} : {{item.value}}
</div>

<div *ngFor="let item of object | keyvalue: keyDescOrder">
  {{item.key}} : {{item.value}}
</div>

See this stackblitz for a demo.

查看更多
孤傲高冷的网名
4楼-- · 2019-02-25 18:59

Yes, Object properties iterates randomly since it doesn't get stored as array in memory. However you can sort by properties.

If you want to iterate by insertion position, you need to create one extra property like index and set the timestamp and sort by index.

Below is the pipe you can use to control the sorting and iteration

Pipe

import {Pipe, PipeTransform} from 'angular2/core';

@Pipe({name: 'values'})
export class ValuesPipe implements PipeTransform {
    transform(value: any, args?: any[]): Object[] {
        let keyArr: any[] = Object.keys(value),
            dataArr = [],
            keyName = args[0];

        keyArr.forEach((key: any) => {
            value[key][keyName] = key;
            dataArr.push(value[key])
        });

        if(args[1]) {
            dataArr.sort((a: Object, b: Object): number => {
                return a[keyName] > b[keyName] ? 1 : -1;
            });
        }

        return dataArr;
    }
}

Usage

<div *ngFor='#item in object | values:"keyName":true'>...</div>
查看更多
登录 后发表回答