Javascript 在 AngularJS 中过滤对象映射而不是数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13887504/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Filtering on object map rather than array in AngularJS
提问by mbrevoort
Given a controller with a $scope property that is an object with other properties rather than an array like below, how should I filter the ng-repeatset?
给定一个带有 $scope 属性的控制器,它是一个具有其他属性的对象而不是像下面这样的数组,我应该如何过滤该ng-repeat集合?
Here is a JSFiddle: http://jsfiddle.net/ZfGx4/110/
这是一个 JSFiddle:http: //jsfiddle.net/ZfGx4/110/
Controller:
控制器:
function HelloCntl($scope, $filter) {
$scope.friends = {
john: {
name: 'John',
phone: '555-1276'
},
mary: {
name: 'Mary',
phone: '800-BIG-MARY'
},
mike: {
name: 'Mike',
phone: '555-4321'
},
adam: {
name: 'Adam',
phone: '555-5678'
},
julie: {
name: 'Julie',
phone: '555-8765'
}
};
}?
Template:
模板:
<div ng:app>
<div ng-controller="HelloCntl">
<input placeholder="Type to filter" ng-model="query">
<ul>
<li ng-repeat="(id, friend) in friends | filter:query">
<span>{{friend.name}} @ {{friend.phone}}</span>
</li>
</ul>
</div>
</div>
回答by jaime
I would change my data structure to an array. Anyway, here's another implementation to filter your friends object.
我会将我的数据结构更改为数组。无论如何,这是过滤朋友对象的另一种实现。
angular.module('filters',['utils'])
.filter('friendFilter', function(utils){
return function(input, query){
if(!query) return input;
var result = [];
angular.forEach(input, function(friend){
if(utils.compareStr(friend.name, query) ||
utils.compareStr(friend.phone, query))
result.push(friend);
});
return result;
};
});
This iterates over the object only once, compares by nameand phoneand can be called like this.
这仅迭代对象一次,通过name和进行比较phone并且可以像这样调用。
<li ng-repeat="friend in friends | friendFilter:query">
I defined the compareStrin another module, but you don't really need to do it.
我compareStr在另一个模块中定义了,但您实际上并不需要这样做。
angular.module('utils', [])
.factory('utils', function(){
return{
compareStr: function(stra, strb){
stra = ("" + stra).toLowerCase();
strb = ("" + strb).toLowerCase();
return stra.indexOf(strb) !== -1;
}
};
});
Don't forget to inject the filtersmodule into your app
不要忘记将filters模块注入您的应用程序
angular.module('app',['filters'])
Here's the full example: http://jsbin.com/acagag/5/edit
这是完整的示例:http: //jsbin.com/acagag/5/edit
回答by garst
I guess you can't do it directly with 'filter'. Looking at the code in angular.js, these are the first lines of the filter function:
我想你不能直接用'过滤器'来做。查看 angular.js 中的代码,这些是过滤器函数的第一行:
function filterFilter() {
return function(array, expression) {
if (!(array instanceof Array)) return array;
So if it receives something different from an array, it does nothing.
因此,如果它接收到与数组不同的东西,它什么也不做。
Here is one way to do it, not sure if I would recommend it, but it's is an idea:
这是一种方法,不确定我是否会推荐它,但这是一个想法:
In the controller, just convert to an array before passing it to the filter:
在控制器中,只需在将其传递给过滤器之前转换为数组:
$scope.filteredFriends = function() {
var array = [];
for(key in $scope.friends) {
array.push($scope.friends[key]);
}
return $filter('filter')(array, $scope.query);
}
And the ng-repeat:
和 ng-repeat:
<li ng-repeat="friend in filteredFriends()">
Example: http://jsbin.com/acagag/2/edit
示例:http: //jsbin.com/acagag/2/edit
Maybe a better solution is to write a custom filter.
也许更好的解决方案是编写自定义过滤器。
回答by charlesgres
I had the same problem, and succeeded by creating my own filter that accepts a map, while still using the built-in filter for doing the actual matching.
我遇到了同样的问题,并通过创建我自己的接受地图的过滤器成功,同时仍然使用内置过滤器进行实际匹配。
My custom filter traverses the map, and for each element calls the built-in filter, but given that that filter only accepts an array, I wrap each element in an array of length 1 (the [data] below). So the match succeeds if the output-array's length is still 1.
我的自定义过滤器遍历地图,并为每个元素调用内置过滤器,但鉴于该过滤器只接受一个数组,我将每个元素包装在一个长度为 1 的数组中(下面的 [数据])。因此,如果输出数组的长度仍为 1,则匹配成功。
.filter('mapFilter', function($filter) {
var filter = $filter('filter');
return function(map, expression, comparator) {
if (! expression) return map;
var result = {};
angular.forEach(map, function(data, index) {
if (filter([data], expression, comparator).length)
result[index] = data;
});
return result;
}
})
This setup loses efficiency of course because the built-in filter is required to determine what it needs to do for each element in the map, instead of only once if you give it an array with all elements, but in my case, with a map of 500 elements the filtering is still instanteanous.
这种设置当然会降低效率,因为需要内置过滤器来确定它需要为地图中的每个元素做什么,而不是如果你给它一个包含所有元素的数组,而不是只有一次,但在我的情况下,使用地图500 个元素的过滤仍然是即时的。
回答by redben
Not an optimal solution but if you want something quick and dirty :
不是最佳解决方案,但如果您想要快速而肮脏的东西:
<li ng-repeat="(id, friend) in friends | filter:query" ng-hide="id !== query.id">
<span>{{friend.name}} @ {{friend.phone}}</span>
</li>
Or ng-ifinstead of ng-hide
或者ng-if代替ng-hide
回答by Kevin Simper
I made an example on how to not change your object to an Array. I think this answers the question more correct.
我做了一个关于如何不将对象更改为数组的示例。我认为这更正确地回答了这个问题。
I had the same problem that i could not search in a Object.
我有同样的问题,我无法在对象中搜索。
http://jsbin.com/acagag/223/edit
http://jsbin.com/acagag/223/edit
angular.module('filters',['utils'])
.filter('friendFilter', function(utils){
return function(input, query){
if(!query) return input;
var result = {};
angular.forEach(input, function(friendData, friend){
if(utils.compareStr(friend, query) ||
utils.compareStr(friendData.phone, query))
result[friend] = friendData;
});
return result;
};
});
So just instead of returning a array you return a object.
所以只是返回一个对象而不是返回一个数组。
Hope this helps someone!
希望这对某人有帮助!
回答by darksioul
Rather than using a filter you can also simply :
除了使用过滤器,您还可以简单地:
$http.get('api/users').success(function(data){
angular.forEach(data, function(value, key){
users.push(value);
});
$scope.users = users;
});
And in the template
并在模板中
<input type="text" ng-model="query" placeholder="Search user"/>
<li ng-repeat="user in users | filter:query">
{{ user.name }}
</li>

