How to iterate through JavaScript maps using ng-repeat in angularjs?

I try to use JavaScript Maps in the ng-repeat angular directive while searching, I found that this can be done as follows:

<ul ng-controller="MyCtrl"> <li ng-repeat='(key, value) in {"First Name":"John", "Last Name":"Smith"}'> <span>Key: {{key}}, value: {{value}}</span> </li> </ul> 

but this only works with regular JSON objects, when I create a real map as follows, it does not work.

I have this controller, for example

 function MyCtrl($scope) { $scope.items = new map(); $scope.items.set('adam',{'age':10,'fav':'doogie'}); $scope.items.set('amalie',{'age':12}); } 

and this html code

 <ul> <li ng-repeat='(key, value) in items'> <span>Key: {{key}}, value: {{value}}</span> </li> </ul> 
+2
javascript angularjs angularjs-ng-repeat
May 19 '17 at 14:56
source share
3 answers

since ng-repeat does not support Map iteration, you can use the custom fromMap filter as shown below

 angular.module('app', []).filter('fromMap', function() { return function(input) { var out = {}; input.forEach((v, k) => out[k] = v); return out; }; }).controller('ctrl',function ($scope) { $scope.items = new Map(); $scope.items.set('adam',{'age':10,'fav':'doogie'}); $scope.items.set('amalie',{'age':12}); $scope.logAdamAge = function() { console.log($scope.items.get("adam").age) }; }); 
 <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> <div ng-app="app" ng-controller="ctrl"> <div>with Map</div> <ul> <li ng-repeat="(key, value) in items | fromMap"> <div>{{key}}</div> <div ng-repeat="(k, v) in value">{{k}}: <input ng-model="value[k]" /></div> </li> </ul> <pre>{{items | fromMap}}</pre> <button ng-click="logAdamAge()">log Adam age from Map</button> </div> 
+3
May 19 '17 at 15:51
source share

this will not work because javascript Map is an iterable object (you can iterate only through entries iterator, each time calling next () and not directly supported by angular ng-repeat .

what can you do if you have existing code to convert an iterable object (map) into a simple array

 $scope.itemsToArray = Array.from($scope.items.entries()); 

this will make your iterative object an array, at this point you can execute the loop in the standard way

 <ul> <li ng-repeat='item in itemsToArray'> <span>Key: {{item[0]}}, value: {{item[1]}}</span> </li> </ul> 

working plnkr here

+1
May 19 '17 at 15:48
source share

Although I like the Jag answer , I created a more extensive snippet with different implementations to achieve the same thing, and I extracted most of the ES6 arrow functions and distributed the operator to implement the filter as a one-line: .filter('fromMap', () => mapObject => [...mapObject])

One setting of the observer and even incomprehensible to this observer.

Here's how you can implement ng-repeat in objects of the Map class:

 angular.module('ui.bootstrap.demo', ['ngAnimate', 'ngSanitize', 'ui.bootstrap']); angular.module('ui.bootstrap.demo') .filter('fromMap', () => mapObject => [...mapObject]) .controller('myCtrl', function($scope, $log) { $scope.myMap = new Map([ ['key1', 'value1'], ['key2', 'value2'], ['key3', 'value3'], ['key4', 'value4'], ]); const unsuscribeWatcher1 = $scope.$watch(() => $scope.myMap.size, (newVal, oldVal) => { if (newVal !== oldVal) { //Splicing and pushing keeps the reference to the Array instead of reassigning. $scope.myLoopedMap.splice(0); $scope.myLoopedMap.push(...[...$scope.mySet].filter(k => $scope.myMap.has(k)).map(k => $scope.myMap.get(k))) $scope.myArrFromMap.splice(0); $scope.myArrFromMap.push(...[...$scope.myMap]) } }) const unsuscribeWatcher2 = $scope.$watch(() => $scope.mySet.size, (newVal, oldVal) => { if (newVal !== oldVal) { $scope.myLoopedMap.splice(0); $scope.myLoopedMap.push([...$scope.mySet].filter(k => $scope.myMap.has(k)).map(k => $scope.myMap.get(k))); } }) $scope.mySet = new Set(['key1', 'key3']); $scope.mySet.add('not in the Map') $scope.mySet.add('key7') $scope.myKeys = ['key1', 'key3']; $scope.myArr = [ ['key1', 'value1'], ['key2', 'value2'], ['key3', 'value3'], ['key4', 'value4'], ]; $scope.myArrFromMap = [...$scope.myMap] $scope.myLoopedMap = [...$scope.mySet].filter(k => $scope.myMap.has(k)).map(k => $scope.myMap.get(k)) $scope.myLoopedMap2 = [...$scope.myKeys].reduce((acc, k) => { return $scope.myMap.has(k) ? acc.concat($scope.myMap.get(k)) : acc; }, []) // added to the map later setTimeout(() => { $scope.$apply(() => { // this will be updated as we are watching the Map $scope.myMap.set('key7', 'value7') }) setTimeout(() => { unsuscribeWatcher1(); // this breaks the watching of the Map $scope.$apply(() => { // this will not be updated as the watcher is not working anymore $scope.myMap.set('key8', 'value8') }) }, 3000) }, 3000) }); 
 <!doctype html> <html ng-app="ui.bootstrap.demo"> <head> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-animate.js"></script> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-sanitize.js"></script> <script src="//angular-ui.imtqy.com/bootstrap/ui-bootstrap-tpls-2.5.0.js"></script> <script src="example.js"></script> </head> <body> <div ng-controller="myCtrl"> <h3>Some test data data</h3> <div>Get 'key1'======> {{myMap.get('key1')}}</div> <div>Arr ==========> {{myArr}}</div> <div>filtered ======> {{myMap | fromMap}}</div> <div>myArrFromMap=> {{myArrFromMap}}</div> <div>myLoopedMap==> {{myLoopedMap}}</div> <div>myLoopedMap2=> {{myLoopedMap2}}</div> <h3>ng repeat in myLoopedMap</h3> <div ng-repeat="item in myLoopedMap"> Item:`{{item}}` </div> <h3>ng repeat in myArrFromMap</h3> <div ng-repeat="(index, value) in myArrFromMap"> value[0]:`{{value[0]}}`, value[1]:`{{value[1]}}`, index: `{{index}}` </div> </div> </body> </html> 

And the corresponding Plnkr

0
Dec 21 '17 at 14:10
source share



All Articles