angular keyvalue pipe sort properties / iterate in order

前端 未结 11 919
有刺的猬
有刺的猬 2020-11-29 21:01

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

相关标签:
11条回答
  • 2020-11-29 21:24

    According to the Angular documentation, the keyvalue pipe sorts the items by key order by default. You can provide a comparer function to change that order, and sort the items according to the key, to the value, or to the entry order of the properties in the object.

    The following comparer functions sort the items in various orders:

    // Preserve original property order
    originalOrder = (a: KeyValue<number,string>, b: KeyValue<number,string>): number => {
      return 0;
    }
    
    // Order by ascending property value
    valueAscOrder = (a: KeyValue<number,string>, b: KeyValue<number,string>): number => {
      return a.value.localeCompare(b.value);
    }
    
    // Order by descending property key
    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: originalOrder">
      {{item.key}} : {{item.value}}
    </div>
    
    <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.


    Supplying a constant or null instead of a valid comparer function preserves the entry order of the object properties, like originalOrder does, but it causes an exception (see this stackblitz):

    <!-- The following syntaxes preserve the original property order -->
    <div *ngFor="let item of object | keyvalue: 0">
    <div *ngFor="let item of object | keyvalue: 374">
    <div *ngFor="let item of object | keyvalue: null">
    
    <!-- but they cause an exception (visible in the console) -->
    ERROR TypeError: The comparison function must be either a function or undefined
    

    Moreover, using that syntax twice in the template does not display the items at all. Therefore, I would not recommend it. Please note that supplying undefined as the comparer function does not cause any exception but does not change the default behavior: the items are sorted by key value.

    0 讨论(0)
  • 2020-11-29 21:24

    I think this is a cleaner solution. Uncomment the return statement that needs to give the right order:

    interface KeyValue<K, V> {
      key: K,
      value: V
    }
    
    // Order by descending property key
      keyOrder = (aA: KeyValue<string,any>, bB: KeyValue<string,any>): number => {
        const a = aA.value.index;
        const b = bB.value.index;
        //return a > b ? 1 : (b > a ? -1 : 0); // ASCENDING
        return a > b ? -1 : (b > a ? 1 : 0); // DESCENDING
      }
    

    USE CASE

    <div *ngFor="let x of y | keyvalue: keyOrder;">
       {{ x.key  }} indexes: {{ x.value.index }}
    </div>
    
    0 讨论(0)
  • 2020-11-29 21:25

    I prefer overriding default keyvalue behavior by extending it in my pipe. Then I use my pipe instead of keyvalue in my templates.

    import {Pipe} from '@angular/core';
    import {KeyValuePipe} from '@angular/common';
    
    const keepOrder = (a, b) => a;
    
    // This pipe uses the angular keyvalue pipe. but doesn't change order.
    @Pipe({
      name: 'defaultOrderKeyvalue'
    })
    export class DefaultOrderKeyvaluePipe extends KeyValuePipe {
    
      public transform(value, compareFn = keepOrder) {
        return super.transform(value, compareFn);
      }
    
    }
    
    0 讨论(0)
  • 2020-11-29 21:29

    Make a pipe to set default to unordered:

    // src/app/pipes/new-key-value.pipe.ts
    import { Pipe, PipeTransform } from '@angular/core';
    import { KeyValuePipe } from '@angular/common';
    import { KeyValueDiffers } from '@angular/core';
    const unordered = (a,b)=>0
    
    @Pipe({
      name: 'newkeyvalue'
    })
    
    // This pipe uses the angular keyvalue pipe. but defaults to unordered.
    export class NewKeyValuePipe implements PipeTransform {
    
      constructor(public differs: KeyValueDiffers){};
      public transform (value, compareFn = unordered){
        let pipe =  new KeyValuePipe(this.differs);
        return pipe.transform(value, compareFn)
      }
    }
    

    links:

    Can I call an Angular2 pipe from a pipe?

    https://github.com/angular/angular/blob/8.2.14/packages/common/src/pipes/keyvalue_pipe.ts#L25-L89

    Template usage:

    // src/app/some-component/some-component.html
    <div *ngFor="let x of myObject | newkeyvalue>
    </div>
    

    register in the module.ts

    // src/app/app.module.ts
    import { NewKeyValuePipe } from '@/pipes/new-key-value.pipe.ts'
    ...
    @NgModule({
      declarations: [
        ...
        NewKeyValuePipe,
        ...
      ]
    ...
    })
    
    0 讨论(0)
  • 2020-11-29 21:30

    Try below piece of code:

    <div *ngFor="let item of object | keyvalue: 0">
      {{item.key}} : {{item.value}}
    </div>
    
    0 讨论(0)
  • 2020-11-29 21:31

    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<string, any>, bkv: KeyValue<string, 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>
    
    0 讨论(0)
提交回复
热议问题