AngularJS 中嵌套对象的自定义 orderBy
Custom orderBy for nested objects in AngularJS
我正在尝试通过嵌套 属性 对数组中的所有对象进行排序,在我的例子中是 validUntil
字段。我只是不知道该怎么做?
我正在使用 angular 和 ng-repeat 循环遍历我的对象。用自定义过滤器扩展它会很棒(这样我就可以创建多个 orderby 字段)
我在SO上搜索过,但没有找到任何适合此类对象结构的解决方案。
更新
所有 validUntil 字段都是纪元时间戳。所以我的输出应该像 validUntil 字段上的升序或降序。这可能吗?我想我需要将我的 checkin 和 fans 对象分开并创建一个新数组来实现这一点?
[{
"19852" : {
"checkins" : {
"-KJk_QqoIMQi_XT4V-e8" : {
"called" : false,
"createdAt" : 1465398937,
"daysBetween" : 22,
"new" : 2000,
"old" : 996,
"ratio" : 45.54545454545455,
"type" : "checkins",
"validUntil" : 1467324000
}
},
"fans" : {
"-KLL5pZsdZu2lAbmIuED" : {
"called" : false,
"createdAt" : 1467102227,
"daysBetween" : 3,
"new" : 500,
"old" : 173,
"ratio" : 109,
"type" : "fans",
"validUntil" : 1467324000
},
"-KLLqu_BT6cIVf-ALJMA" : {
"called" : false,
"createdAt" : 1467114826,
"daysBetween" : 2,
"new" : 600,
"old" : 174,
"ratio" : 213,
"type" : "fans",
"validUntil" : 1467324000
}
},
"name" : "Test 1"
},
"-KCGLvKjmF0dxe8QuAXh" : {
"checkins" : {
"-KLRVY9FAzHDPTIf1_qS" : {
"called" : false,
"createdAt" : 1467209626,
"daysBetween" : 32,
"new" : 4000,
"old" : 3699,
"ratio" : 6.9,
"type" : "checkins",
"validUntil" : 1470002400
}
},
"name" : "Test 2"
},
"-KKOX2JDkM84jrZcHHq4" : {
"fans" : {
"-KL253oeqDFedCRpDV4a" : {
"called" : false,
"createdAt" : 1466783256,
"daysBetween" : 6,
"new" : 10,
"old" : 1,
"ratio" : 1.5,
"type" : "fans",
"validUntil" : 1467324000
}
},
"name" : "Test 3"
}
}]
AngularJs的OrderBy不允许对对象进行排序。要解决这个问题,您可以自己将对象转换为数组,或者创建一个新的过滤器在幕后执行此操作。
以下是如何通过自定义过滤器进行操作。请注意函数 getMinValue 是递归的并且不处理循环引用(它们会一直循环)。如果您遇到这个问题,您只需要修改此函数以不递归调用某些键。
这里是 javascript 代码:
angular.module("myApp", []).filter('orderObjectBy', function(orderByFilter) {
return function(items, sortPredicate, reverseOrder) {
var array= [];
angular.forEach(items, function(item) {
array.push(item);
});
return orderByFilter(array, sortPredicate, reverseOrder);
};
}).controller('someController', function ($scope) {
$scope.order = function(obj){
return getMinValue(obj);
};
function getMinValue(obj){
//this is a recursive call that will look through all of the objects to find the minimum validUntil. Be careful because circular references will loop forever.
//if you believe you might have circular references, then there are small changes you can make to account for that. It just didn't seem necessary for your code.
var minValidUntil = null;
angular.forEach(obj, function(item) {
var validUntil = item.validUntil;
if(validUntil == null && angular.isObject(item)){
validUntil = getMinValue(item);
}
if(validUntil != null && (minValidUntil == null || validUntil < minValidUntil)){
minValidUntil = validUntil;
}
});
return minValidUntil;
}
$scope.data = {
"19852" : {
"checkins" : {
"-KJk_QqoIMQi_XT4V-e8" : {
"called" : false,
"createdAt" : 1465398937,
"daysBetween" : 22,
"new" : 2000,
"old" : 996,
"ratio" : 45.54545454545455,
"type" : "checkins",
"validUntil" : 1467324000
}
},
"fans" : {
"-KLL5pZsdZu2lAbmIuED" : {
"called" : false,
"createdAt" : 1467102227,
"daysBetween" : 3,
"new" : 500,
"old" : 173,
"ratio" : 109,
"type" : "fans",
"validUntil" : 1467324000
},
"-KLLqu_BT6cIVf-ALJMA" : {
"called" : false,
"createdAt" : 1467114826,
"daysBetween" : 2,
"new" : 600,
"old" : 174,
"ratio" : 213,
"type" : "fans",
"validUntil" : 1467324000
}
},
"name" : "Test 1"
},
"-KCGLvKjmF0dxe8QuAXh" : {
"checkins" : {
"-KLRVY9FAzHDPTIf1_qS" : {
"called" : false,
"createdAt" : 1467209626,
"daysBetween" : 32,
"new" : 4000,
"old" : 3699,
"ratio" : 6.9,
"type" : "checkins",
"validUntil" : 1470002400
}
},
"name" : "Test 2"
},
"-KKOX2JDkM84jrZcHHq4" : {
"fans" : {
"-KL253oeqDFedCRpDV4a" : {
"called" : false,
"createdAt" : 1466783256,
"daysBetween" : 6,
"new" : 10,
"old" : 1,
"ratio" : 1.5,
"type" : "fans",
"validUntil" : 1467324000
}
},
"name" : "Test 3"
}
};
});
这是我用来测试的html:
<div ng-app="myApp" ng-controller="someController">
<div ng-repeat='obj in data | orderObjectBy: order'>
<span>{{obj.name}}</span>
<div ng-repeat='checkin in obj.checkins'>
<span>checkin - {{checkin.validUntil}}</span>
</div>
<div ng-repeat='fan in obj.fans'>
<span>fan - {{fan.validUntil}}</span>
</div>
<br /><br />
</div>
</div>
我正在尝试通过嵌套 属性 对数组中的所有对象进行排序,在我的例子中是 validUntil
字段。我只是不知道该怎么做?
我正在使用 angular 和 ng-repeat 循环遍历我的对象。用自定义过滤器扩展它会很棒(这样我就可以创建多个 orderby 字段)
我在SO上搜索过,但没有找到任何适合此类对象结构的解决方案。
更新 所有 validUntil 字段都是纪元时间戳。所以我的输出应该像 validUntil 字段上的升序或降序。这可能吗?我想我需要将我的 checkin 和 fans 对象分开并创建一个新数组来实现这一点?
[{
"19852" : {
"checkins" : {
"-KJk_QqoIMQi_XT4V-e8" : {
"called" : false,
"createdAt" : 1465398937,
"daysBetween" : 22,
"new" : 2000,
"old" : 996,
"ratio" : 45.54545454545455,
"type" : "checkins",
"validUntil" : 1467324000
}
},
"fans" : {
"-KLL5pZsdZu2lAbmIuED" : {
"called" : false,
"createdAt" : 1467102227,
"daysBetween" : 3,
"new" : 500,
"old" : 173,
"ratio" : 109,
"type" : "fans",
"validUntil" : 1467324000
},
"-KLLqu_BT6cIVf-ALJMA" : {
"called" : false,
"createdAt" : 1467114826,
"daysBetween" : 2,
"new" : 600,
"old" : 174,
"ratio" : 213,
"type" : "fans",
"validUntil" : 1467324000
}
},
"name" : "Test 1"
},
"-KCGLvKjmF0dxe8QuAXh" : {
"checkins" : {
"-KLRVY9FAzHDPTIf1_qS" : {
"called" : false,
"createdAt" : 1467209626,
"daysBetween" : 32,
"new" : 4000,
"old" : 3699,
"ratio" : 6.9,
"type" : "checkins",
"validUntil" : 1470002400
}
},
"name" : "Test 2"
},
"-KKOX2JDkM84jrZcHHq4" : {
"fans" : {
"-KL253oeqDFedCRpDV4a" : {
"called" : false,
"createdAt" : 1466783256,
"daysBetween" : 6,
"new" : 10,
"old" : 1,
"ratio" : 1.5,
"type" : "fans",
"validUntil" : 1467324000
}
},
"name" : "Test 3"
}
}]
AngularJs的OrderBy不允许对对象进行排序。要解决这个问题,您可以自己将对象转换为数组,或者创建一个新的过滤器在幕后执行此操作。
以下是如何通过自定义过滤器进行操作。请注意函数 getMinValue 是递归的并且不处理循环引用(它们会一直循环)。如果您遇到这个问题,您只需要修改此函数以不递归调用某些键。
这里是 javascript 代码:
angular.module("myApp", []).filter('orderObjectBy', function(orderByFilter) {
return function(items, sortPredicate, reverseOrder) {
var array= [];
angular.forEach(items, function(item) {
array.push(item);
});
return orderByFilter(array, sortPredicate, reverseOrder);
};
}).controller('someController', function ($scope) {
$scope.order = function(obj){
return getMinValue(obj);
};
function getMinValue(obj){
//this is a recursive call that will look through all of the objects to find the minimum validUntil. Be careful because circular references will loop forever.
//if you believe you might have circular references, then there are small changes you can make to account for that. It just didn't seem necessary for your code.
var minValidUntil = null;
angular.forEach(obj, function(item) {
var validUntil = item.validUntil;
if(validUntil == null && angular.isObject(item)){
validUntil = getMinValue(item);
}
if(validUntil != null && (minValidUntil == null || validUntil < minValidUntil)){
minValidUntil = validUntil;
}
});
return minValidUntil;
}
$scope.data = {
"19852" : {
"checkins" : {
"-KJk_QqoIMQi_XT4V-e8" : {
"called" : false,
"createdAt" : 1465398937,
"daysBetween" : 22,
"new" : 2000,
"old" : 996,
"ratio" : 45.54545454545455,
"type" : "checkins",
"validUntil" : 1467324000
}
},
"fans" : {
"-KLL5pZsdZu2lAbmIuED" : {
"called" : false,
"createdAt" : 1467102227,
"daysBetween" : 3,
"new" : 500,
"old" : 173,
"ratio" : 109,
"type" : "fans",
"validUntil" : 1467324000
},
"-KLLqu_BT6cIVf-ALJMA" : {
"called" : false,
"createdAt" : 1467114826,
"daysBetween" : 2,
"new" : 600,
"old" : 174,
"ratio" : 213,
"type" : "fans",
"validUntil" : 1467324000
}
},
"name" : "Test 1"
},
"-KCGLvKjmF0dxe8QuAXh" : {
"checkins" : {
"-KLRVY9FAzHDPTIf1_qS" : {
"called" : false,
"createdAt" : 1467209626,
"daysBetween" : 32,
"new" : 4000,
"old" : 3699,
"ratio" : 6.9,
"type" : "checkins",
"validUntil" : 1470002400
}
},
"name" : "Test 2"
},
"-KKOX2JDkM84jrZcHHq4" : {
"fans" : {
"-KL253oeqDFedCRpDV4a" : {
"called" : false,
"createdAt" : 1466783256,
"daysBetween" : 6,
"new" : 10,
"old" : 1,
"ratio" : 1.5,
"type" : "fans",
"validUntil" : 1467324000
}
},
"name" : "Test 3"
}
};
});
这是我用来测试的html:
<div ng-app="myApp" ng-controller="someController">
<div ng-repeat='obj in data | orderObjectBy: order'>
<span>{{obj.name}}</span>
<div ng-repeat='checkin in obj.checkins'>
<span>checkin - {{checkin.validUntil}}</span>
</div>
<div ng-repeat='fan in obj.fans'>
<span>fan - {{fan.validUntil}}</span>
</div>
<br /><br />
</div>
</div>