37

我正在订购我的数据,它的工作一切正常,除了某些字段为空或没有价值。订购时,这些空白字段首先出现。例如,在订购数字时,我们会在获得“0”值之前获得一个巨大的空列表。

我这样做是这样的:

ng-click="predicate = 'name'; reverse=!reverse"

ng-repeat="name in names | orderBy:predicate:reverse"

JSFiddle:http: //jsfiddle.net/JZuCX/1/

有没有一种简单优雅的方法来解决这个问题?无论如何,我希望空字段排在最后。

4

9 回答 9

63

如何对字符串进行排序:

item in (items|orderBy:['!name', 'name'])

优点(除了更简洁之外)是使用空白字符串对null&进行排序。undefined

在我的情况下,我希望将空白、空值和未定义放在顶部(默认情况下,空值和未定义排序到底部),所以我使用了:

item in (items|orderBy:['!!name', 'name'])
于 2015-10-22T16:41:31.893 回答
43

我会编写一个过滤器,从有序数组中获取具有空名称的项目并将它们放在最后:

<li ng-repeat="item in (items|orderBy:'name'|emptyToEnd:'name')">{{item.name}}</li>

代码可能如下所示:

.filter("emptyToEnd", function () {
    return function (array, key) {
        if(!angular.isArray(array)) return;
        var present = array.filter(function (item) {
            return item[key];
        });
        var empty = array.filter(function (item) {
            return !item[key]
        });
        return present.concat(empty);
    };
});

工作示例

顺便说一句,您的小提琴不包含任何相关代码。您是否使用了错误的链接?

更新 2: 你在摆弄我的过滤器。

于 2013-09-04T02:55:21.970 回答
16

下来这里!:D

此解决方案扩展了 angularJs过滤器的正常功能orderBy,以采用第三个参数来指定是否反转空值和未定义值的正常排序。它观察它传递的属性名称(不仅仅是一个),并且不会像其他一些解决方案那样一秒钟迭代项目。它是这样使用的:

<li ng-repeat="item in (items|orderBy:'name':false:true)">{{item.name}}</li>

我找到了一堆线程,其中一些不是直接的 about orderBy,并将他们的技术和我自己的一些技术编译成这个:

angular.module('lib')
.config(['$provide', function ($provide) {
    $provide.decorator('orderByFilter', ['$delegate', '$parse', function ($delegate, $parse) {
        return function () {
            var predicates = arguments[1];
            var invertEmpties = arguments[3];
            if (angular.isDefined(invertEmpties)) {
                if (!angular.isArray(predicates)) {
                    predicates = [predicates];
                }
                var newPredicates = [];
                angular.forEach(predicates, function (predicate) {
                    if (angular.isString(predicate)) {
                        var trimmed = predicate;
                        if (trimmed.charAt(0) == '-') {
                            trimmed = trimmed.slice(1);
                        }
                        var keyFn = $parse(trimmed);
                        newPredicates.push(function (item) {
                            var value = keyFn(item);
                            return (angular.isDefined(value) && value != null) == invertEmpties;
                        })
                    }
                    newPredicates.push(predicate);
                });
                predicates = newPredicates;
            }
            return $delegate(arguments[0], predicates, arguments[2]);
        }
    }])
}]);

要逐字使用此代码,请将“lib”指定为您的应用程序的依赖项。

学分:

于 2015-05-04T11:18:37.130 回答
4

我不相信有一个“开箱即用”的解决方案。我很容易出错。这是我尝试使用函数作为谓词的解决方案:

ng-repeat="name in names | orderBy:predicate"

在您的控制器内部:

$scope.predicate = function(name) {
    return name === '' ? 'zzzzzzz' : !name; 
    /* The 'zzzzzz' forces the empty names to the end, 
      I can't think of a simpler way at the moment. */
}
于 2013-09-04T03:03:24.433 回答
4

除了 Klaster_1 的解决方案外,增加一个额外的参数,使过滤器更通用:

http://jsfiddle.net/Zukzuk/JZuCX/27/

执行

<tr ng-repeat="name in (names | orderBy:predicate:reverse | orderEmpty:'name':'toBottom')">

筛选

.filter('orderEmpty', function () {
    return function (array, key, type) {
        var present, empty, result;

        if(!angular.isArray(array)) return;

        present = array.filter(function (item) {
            return item[key];
        });

        empty = array.filter(function (item) {
            return !item[key]
        });

        switch(type) {
            case 'toBottom':
                result = present.concat(empty);
                break;
            case 'toTop':
                result = empty.concat(present);
                break;

                // ... etc, etc ...

            default:
                result = array;
                break;
        }
        return result;
    };
});

Thnx Klaster_1!

于 2015-01-15T12:35:05.763 回答
2

使用可变排序列进行排序和反向排序,并将未定义保持在底部,甚至低于负值

我喜欢上面肖恩回答的优雅!我需要让我的用户能够选择要排序的列和排序方向的选择,但即使有负数,仍然需要未定义的降到底部。

肖恩修复负数的关键见解是!!。如果您正在执行正向排序,请使用“!”+谓词,如果您正在执行反向排序,请使用“!”+谓词。

下面的代码片段演示了这一点。顺便说一句,我已经将设置谓词(要排序的属性的选择)和反转的变量放在对象(“d”)中,这样我们就不会遇到奇怪的范围问题。您的环境中可能不需要“d.”。

此外,您可能希望使用比我在页面底部的蹩脚按钮更好的东西来控制您的排序谓词和方向。但是,这使代码的关键部分易于阅读。

function mainController($scope) {
  $scope.userArray = [
  { name: "Don", age: 20 },
  { name: "Bob", age: 30, height: 170 },
  { name: "Abe", age: 40, height: 160 },
  { name: "Zoe", age: 70 },
  {              age: 70, height: 155 },
  { name: "Shorty",age:45,height: -200},
  { name: "TwinkleInEye", age: -1, height: 152 }
  ]

  $scope.d = {}; // Create an object into which info can be stored and not trashed by Angular's tendency to add scopes
  $scope.d.predicate = "name"; // This string is the name of the property on which to sort
  $scope.d.reverse = false; // True means reverse the sort order
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<body ng-app="" ng-controller="mainController">
  <div ng-repeat="user in (userArray | orderBy: (d.reverse ?['!!'+d.predicate,d.predicate]:['!'+d.predicate,d.predicate]) : d.reverse)">

    Name {{ user.name }} : Age {{ user.age }} : Height {{ user.height }}
  </div>

  <br/>

  <button ng-click="d.predicate='name';">Name</button>
  <button ng-click="d.predicate='age';">Age</button>
  <button ng-click="d.predicate='height';">Height</button> Currently: {{d.predicate}}
 <br/> Leave undefined at bottom, but otherwise: 
  <button ng-click="d.reverse= !d.reverse;">Reverse</button> Currently: {{d.reverse}}

</body>

于 2017-03-19T15:17:24.957 回答
0

@Klaster_1 确实在做某事,但只要我需要一个嵌套值,过滤器就会停止工作。此外,如果我是反向排序,我仍然希望我的空值显示在 0 之前。我添加了 $parse 来处理嵌套键,并添加了一个反向参数,以便我知道何时将空值放在顶部。

.filter("emptyToEnd", function ($parse) {
    return function (array, key, reverse) {
        if(!angular.isArray(array)) return;
        var keyFn = $parse(key);
        var present = [];
        var empty = [];

        angular.forEach(array, function(item){
          var val = keyFn(item);
          if(angular.isUndefined(val) || val === null) {
            empty.push(item);
          } else {
            present.push(item);
          }
        });

        if (reverse) {
          return present.concat(empty);
        } else {
          return empty.concat(present);
        }
    };
});
于 2014-07-10T22:04:43.213 回答
0

我不知道为什么其他答案建议将空值记录放在底部,如果我想正常排序,意味着按 ASC 顺序将所有空值放在顶部,按 DESC 顺序将所有空值放在底部,我尝试了其他答案在这里但无法帮助我更改代码以将我的数组中的 null 转换为 '' 并且它现在可以像这样顺利运行:

$scope.convertNullToBlank = function (array) {
  for (var i = 0; i < array.length; i++) {
     if (array[i].col1 === null)
       array[i].col1 = '';

     if (array[i].col2 === null)
        array[i].col2 = '';
  }
  return array;
}
于 2015-09-08T14:39:46.420 回答
0

我根据以前的解决方案创建了一个带有替代过滤器的要点: https ://gist.github.com/360disrupt/1432ee1cd1685a0baf8967dc70ae14b1

该过滤器扩展了现有的角度过滤器:

angular.module 'tsd.orderByEmptyLast', []
  .filter 'orderByEmptyLast', ($filter) ->
    return (list, predicate, reverse)->
      orderedList = $filter('orderBy')(list, if reverse then ['!' + predicate, '-' + predicate] else ['!' + predicate, predicate] )
      return orderedList

在较新的角度版本上,您可能需要包含orderByFilter而不是使用 $filter

angular.module 'tsd.orderByEmptyLast', ['orderByFilter']
  .filter 'orderByEmptyLast', () ->
    return (list, predicate, reverse)->
      orderedList = orderByFilter(list, if reverse then ['!' + predicate, '-' + predicate] else ['!' + predicate, predicate] )
      return orderedList
于 2017-10-18T12:43:22.010 回答