如何在 angularjs 中使用 ng-repeat 遍历 JavaScript 地图?
How to iterate through JavaScript Maps using ng-repeat in angularjs?
我正在尝试在 ng-repeat angular 的指令中使用 JavaScript 地图
在搜索时我发现可以这样做:
<ul ng-controller="MyCtrl">
<li ng-repeat='(key, value) in {"First Name":"John", "Last Name":"Smith"}'>
<span>Key: {{key}}, value: {{value}}</span>
</li>
</ul>
但这仅适用于普通 JSON 对象,当我按以下方式创建真实地图时,它不起作用。
例如我有这个控制器
function MyCtrl($scope) {
$scope.items = new map();
$scope.items.set('adam',{'age':10,'fav':'doogie'});
$scope.items.set('amalie',{'age':12});
}
和这个html代码
<ul>
<li ng-repeat='(key, value) in items'>
<span>Key: {{key}}, value: {{value}}</span>
</li>
</ul>
这是行不通的,因为 javascript Map is an iterable object (you can loop over only through the entries 迭代器,每次调用 next())并且 angular ng-repeat
不直接支持。
如果您有预先存在的代码,您可以将可迭代对象(映射)转换为普通数组
$scope.itemsToArray = Array.from($scope.items.entries());
这将使您的可迭代对象成为一个数组,此时您可以以标准方式循环
<ul>
<li ng-repeat='item in itemsToArray'>
<span>Key: {{item[0]}}, value: {{item[1]}}</span>
</li>
</ul>
工作计划here
由于 ng-repeat
不支持 Map
迭代,您可以使用自定义过滤器 fromMap
,如下所示
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>
虽然我喜欢 ,但我构建了一个更广泛的片段,使用不同的实现来实现相同的目的,并且我取出了大部分 ES6 箭头函数和扩展运算符来实现过滤器作为一个-班轮:.filter('fromMap', () => mapObject => [...mapObject])
设置观察者甚至退订该观察者。
以下是如何在 Map
class 对象上实施 ng-repeat:
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.github.io/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>
我正在尝试在 ng-repeat angular 的指令中使用 JavaScript 地图 在搜索时我发现可以这样做:
<ul ng-controller="MyCtrl">
<li ng-repeat='(key, value) in {"First Name":"John", "Last Name":"Smith"}'>
<span>Key: {{key}}, value: {{value}}</span>
</li>
</ul>
但这仅适用于普通 JSON 对象,当我按以下方式创建真实地图时,它不起作用。
例如我有这个控制器
function MyCtrl($scope) {
$scope.items = new map();
$scope.items.set('adam',{'age':10,'fav':'doogie'});
$scope.items.set('amalie',{'age':12});
}
和这个html代码
<ul>
<li ng-repeat='(key, value) in items'>
<span>Key: {{key}}, value: {{value}}</span>
</li>
</ul>
这是行不通的,因为 javascript Map is an iterable object (you can loop over only through the entries 迭代器,每次调用 next())并且 angular ng-repeat
不直接支持。
如果您有预先存在的代码,您可以将可迭代对象(映射)转换为普通数组
$scope.itemsToArray = Array.from($scope.items.entries());
这将使您的可迭代对象成为一个数组,此时您可以以标准方式循环
<ul>
<li ng-repeat='item in itemsToArray'>
<span>Key: {{item[0]}}, value: {{item[1]}}</span>
</li>
</ul>
工作计划here
由于 ng-repeat
不支持 Map
迭代,您可以使用自定义过滤器 fromMap
,如下所示
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>
虽然我喜欢 .filter('fromMap', () => mapObject => [...mapObject])
设置观察者甚至退订该观察者。
以下是如何在 Map
class 对象上实施 ng-repeat:
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.github.io/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>