在我的一个项目中有些东西让我疯狂。
我有一些非常类似的代码(我试图使它与我的相似,使用我使用的所有JS文件等,但是这个Plnkr中的代码似乎并不重要,因为你会看到因为我无法在那里重现...): http://plnkr.co/edit/SCUCsxLgu2zFzMhZ0whs?p=preview
我的问题是,当我设置predicate=''
时,排序不会100%清除。 Angular似乎改变了我的元素的顺序(这张图片是predicate=''
):
当我删除orderBy
时,所有内容都按顺序排列(就像它是从我的存储库中提供服务的那样)。在用orderBy
尝试数以百万计不同的事情之后,我无法完全清楚这一点。
我发现这个案例与我有一些相似之处:AngularJS ngRepeat orderBy in Chrome,但事实证明我的案子与该问题无关。
我是一个耐心的人,所以我进入angular.js
文件(AngularJS v1.3.15)并开始调试。这是最重要的一句话:
return slice.call(array).sort(reverseComparator(comparator, reverseOrder));
直到slice.call(array)
数组排序良好。执行sort
时结果错误。所以我这样做了:
function comparator(o1, o2) {
for (var i = 0; i < sortPredicate.length; i++) {
var comp = sortPredicate[i](o1, o2);
if (comp !== 0){
console.log(7); // <---------------------
return comp;
}
}
console.log(0); // <---------------------
return 0;
}
function reverseComparator(comp, descending) {
return descending
? function(a, b) {return comp(b,a);}
: comp;
}
猜猜:当predicate=''
为零时,我进入我的控制台。
另外,输入:
slice.call(array).sort
...返回:
function sort() { [native code] }
所以,我不知道为什么会发生这种排序。 它似乎只发生在基于Chromium的浏览器中(我尝试过Chrome和Opera)。 FF和IE11按预期清除排序。
现在,我认为这是一个Chromium bug,但我还是没有设法在那个Plnkr中重现它,我想知道为什么(数据中可能有不同的东西?)...
我也尝试停用我的Chrome扩展程序,但这似乎没有任何区别。
Chromium和Angular现在都很有名。还有其他人注意过这个吗?
有没有人知道这里有什么问题?
更新
行。我想我已经设法通过向我的阵列添加更多项目来重现它。看这里: http://plnkr.co/edit/SCUCsxLgu2zFzMhZ0whs?p=preview
(派对时间!:D)
我要去向Angular团队报告。他们是谷歌。他们也可以修复Chromium。 :d
答案 0 :(得分:3)
排序不一定稳定(也就是说,比较相等的元素不一定保持原始顺序)。
所以它不是浏览器中的错误。
Angular代码确实考虑了一个空谓词:
if (predicate === '') {
// Effectively no predicate was passed so we compare identity
return reverseComparator(compare, descending);
}
compare
函数
function compare(v1, v2) {
var t1 = typeof v1;
var t2 = typeof v2;
if (t1 === t2 && t1 === "object") {
v1 = objectToString(v1);
v2 = objectToString(v2);
}
...
和objectToString
正在
function objectToString(value) {
if (value === null) return 'null';
if (typeof value.valueOf === 'function') {
value = value.valueOf();
if (isPrimitive(value)) return value;
}
if (typeof value.toString === 'function') {
value = value.toString();
if (isPrimitive(value)) return value;
}
return '';
}
由于您的对象既没有拥有 valueOf
或toString
方法,所以它们最终相等(函数可能会返回"[object Object]"
)。这让我们回到了ECMAScript规范。
答案 1 :(得分:2)
我将最终采用的解决方案是使用这些自定义过滤器:
(function () {
function isNullOrEmpty(str) {
return str === '' || str === undefined || str === null;
}
angular.module('CustomFilters', [])
.filter('okOrderBy', ['$filter', function ($filter) {
return function (array, predicate, reverse) {
if (isNullOrEmpty(predicate)) return array;
return $filter('orderBy')(array, predicate, reverse);
};
}
])
.filter('arrayOrderBy', [function () {
function Comparator(predicate, reverse) {
return reverse ? function (a, b) {
a = a[predicate];
b = b[predicate];
if (a === b) return 0;
return a < b ? 1 : -1;
} : function (a, b) {
a = a[predicate];
b = b[predicate];
if (a === b) return 0;
return a < b ? -1 : 1;
};
}
return function (array, predicate, reverse) {
if (isNullOrEmpty(predicate)) return array;
return array.slice(0).sort(new Comparator(predicate, reverse));
};
}
]);
})();
第二个独立于Angular过滤器,我更喜欢它。
但它仅适用于对象数组,谓词只是属性名称,并且不允许&#34;多列&#34;排序。 虽然第一个应该适用于所有事情(我猜)。
我有一个很大的困境,我应该接受哪个答案,因为所有其他答案都是有用和有趣的。我希望我能不止一次地投票给他们。我正在考虑选择这个答案(我知道......我很自私......)只是因为它解决了问题,而且使用的时间比用户提供的更短“#34;你&#34;。
答案 2 :(得分:1)
另一种方法。当你不想要时,不要让排序运行。
很高兴的角度让你在那里写任何东西。
<tr ng-repeat="friend in (predicate ? (friends | orderBy:predicate:reverse) : friends)">
<td>{{friend.name}}</td>
<td>{{friend.phone}}</td>
<td>{{friend.age}}</td>
</tr>