The KeyValue Pipe converts given Object or Map into an array of key-value pairs. We can use this with the ngFor to loop through the object keys. The keyValue
accepts the one argument compareFn
, which we can use to set the custom sort to the pipe. In this tutorial, let us learn how to make use of KeyValue
pipe with example.
How it works
Consider, that you have the following object and a map object. It has property a
,b
& c
. We cannot use ngFor to iterate over it as it requires an array. This is where the KeyValue
pipe comes into play. It will convert them to an array of key-value pair
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | obj = { c: 123, b: 456, a: 789, }; mapObj = new Map([ ['c', 123], ['b', 446], ['a', 789], ]); |
We use keyvalue
just like any other pipes in Angular and as shown below
1 2 3 4 5 | obj | keyvalue mapObj | keyvalue |
The keyValue
converts them and returns in the following format. each property of the object a: 789
is converted to an object with name as key
and value as value
{ key:a, value:789 }
. It creates array of such objects and returns it.
1 2 3 4 5 6 7 | obj = [ { key:a, value:789 }, { key:b, value:446 }, { key:c, value:123 }, ]; |
Now we can use the ngFor
to loop through it and display the content.
1 2 3 4 5 6 7 8 9 10 11 12 | <ul> <li *ngFor="let item of obj | keyvalue"> {{item.key}} ---> {{item.value}}</li> </ul> //output a ---> 789 b ---> 456 c ---> 123 |
Default Sorting
KeyValue
pipe uses the key
to sort the results array. You can see it from the above example. Even though our object was c
,b
& a
it was sorts it as a
,b
,c
. The keyValue pipe uses the defaultComparator
to sort the result. It uses
- Ascending Order if the keys are number
- Alphabetical Order if keys are strings
- if keys are are of different types. then covert them to to their string values and use Alphabetical Order
- If key is a either Null or undefined, put then at the end of the sort.
Custom Sorting
You can customize it by providing a custom sort function (compareFn
) as the first argument to the keyValue
pipe
The syntax for the compareFn
as shown below. It accepts first & second keyValue
and must return a number. The number must be a zero if values are equivalent else either a negative number or positive number
1 2 3 | compareFn (a: KeyValue, b: KeyValue) => number |
The following are three compareFn
1 2 3 4 5 6 7 8 9 10 11 12 13 | orderOriginal = (a: KeyValue<number,string>, b: KeyValue<number,string>): number => { return 0 } orderbyValueAsc = (a: KeyValue<number,string>, b: KeyValue<number,string>): number => { return a.value > b.value ? -1 : (a.value > b.value) ? 0 : 1 } orderbyValueDsc = (a: KeyValue<number,string>, b: KeyValue<number,string>): number => { return a.value > b.value ? 1 : (a.value > b.value) ? 0 : -1 } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | <ul> <li *ngFor="let item of obj | keyvalue"> {{item.key}} ---> {{item.value}}</li> </ul> //Output a ---> 789 b ---> 456 c ---> 123 <ul> <li *ngFor="let item of obj | keyvalue : orderOriginal"> {{item.key}} ---> {{item.value}}</li> </ul> //Output b ---> 456 c ---> 123 a ---> 78 <ul> <li *ngFor="let item of obj | keyvalue : orderbyValueAsc "> {{item.key}} ---> {{item.value}}</li> </ul> //Output a ---> 789 b ---> 456 c ---> 123 <ul> <li *ngFor="let item of obj | keyvalue : orderbyValueDsc "> {{item.key}} ---> {{item.value}}</li> </ul> //Output c ---> 123 b ---> 456 a ---> 789 |
KeyValue Pipe Example
Consider the following breeds of dogs. The example sorts the list based on the number of sub breeds. The final code is as shown below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | breeds= { "corgi": ["cardigan"], "deerhound": ["scottish"], "bulldog": ["boston", "english", "french"], "mastiff": ["bull", "english", "tibetan"], "australian": ["shepherd"], "greyhound": ["italian"], "buhund": ["norwegian"], "hound": ["afghan", "basset", "blood", "english", "ibizan", "plott", "walker"], "bullterrier": ["staffordshire"], } |
CompareFn
1 2 3 4 5 | orderClause = (a: KeyValue<number,[string]>, b: KeyValue<number,[string]>): number => { return a.value.length > b.value.length ? -1 : (a.value.length > b.value.length) ? 0 : 1 } |
Template
1 2 3 4 5 6 | <ul> <li *ngFor="let item of breeds | keyvalue : orderClause "> {{item.key}} ---> {{item.value}}</li> </ul> |
The output
1 2 3 4 5 6 7 8 9 10 11 | hound ---> afghan,basset,blood,english,ibizan,plott,walker bulldog ---> boston,english,french mastiff ---> bull,english,tibetan corgi ---> cardigan deerhound ---> scottish australian ---> shepherd greyhound ---> italian buhund ---> norwegian bullterrier ---> staffordshire |
Reference
Read More