I’ve been finding myself using Maps and Sets quite a bit lately. This is becoming especially true when I traverse through an array, or array of arrays, reducing it down to a set of unique, or key-value pairs. As a result, I recently had to write a Pipe similar to one that I previously wrote in order to iterate over Map and Set keys and values using ngFor. At the time of this writing, ngFor doesn’t natively support the Set and Map data types.

Iterating Over Sets

Let’s take the easy one first. As you’ve probably seen, traveling through the web, a Set is a specific iterator construct that allows only unique elements. It has many of the same methods as Map, which can be to our advantage.

We can use the Set.values() method to return an array, so that when we send our Set to the Pipe, it will pull all of the values into an array:

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

@Pipe({name: 'setValues'})
export class SetValuesPipe implements PipeTransform {
    transform(value: any, args?: any[]): Object[] {
        return value.values();

Yeah, that was crazy simple. There are alternative ways to do this as well. Instead of the values() method, you could return Array.from(value), which would yield the same result. However this approach would be specific to Set only.

We could also use the above block to iterate over a Map if you wanted to, since the Map.values() property will also return all of the values in the key-value pairs. Just note that you’ll lose the keys, which is probably not what you want. So let’s do something about that.

Iterating Over Maps

Ideally, you’ll want to maintain the key in the key-value pairing when you iterate over a Map. That being the case, you can take the same approach I took when iterating over Object properties, which is to create an array of return objects that have two properties – the key, and the value. Before we do that, let’s take a quick look at the data construct of a Map:

[["key1", "value1"], ["key2", "value2"]]

Each entry is a true key-value pair, so both members of the entry should be treated as equally important, and will need to be included in the return value of our Pipe. Let’s take a look:

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

@Pipe({name: 'mapValues'})
export class MapValuesPipe implements PipeTransform {
    transform(value: any, args?: any[]): Object[] {
        let returnArray = [];

        value.forEach((entryVal, entryKey) => {
                key: entryKey,
                val: entryVal

        return returnArray;

That seems simple enough. We use the built-in forEach() to loop over each entry in the Map, and add each as a property of an object that’s added to a return array.

Further Thoughts

Since we’re looping over iterators, we don’t have to worry about sorting if we want to maintain the same order that they came with. Unlike looping over Objects, we can be sure that the entries in a Map and a Set will maintain their order no matter where we use them.

You could add arguments similar to the one I demonstrated in the previous post, where you dynamically set the property names in the return object. That’s entirely up to you.

It should also be noted that the above code only shows happy-path implementation. If you pass anything to the blocks that doesn’t have the appropriate methods, then you’ll throw an exception. The PipeTransform class is very specific that the value argument needs to be of the type any, but you can extend that, or make a check in your own code to ensure that whatever is passed actually is a Map or a Set.

Leave a Reply