AngularJS orderby与空字段

时间:2013-09-04 02:10:19

标签: javascript angularjs

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

我这样做:

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

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

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

有一种简单优雅的方法来解决这个问题吗?无论如何,我希望空场能够持续到位。

9 个答案:

答案 0 :(得分:57)

如何排序字符串:

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

优点(除了更简洁)是排序null& undefined空白字符串。

在我的情况下,我想要空白&零点和顶部的undefineds(默认情况下为nulls和undefineds排序到底部),所以我使用了:

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

答案 1 :(得分:41)

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

<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);
    };
});

Working example

顺便说一下,你的小提琴不包含任何相关的代码。你使用了错误的链接吗?

更新2: Your fiddle with my filter.

答案 2 :(得分:16)

在这里! :d

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

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

我发现了一堆线程,有些线程并不是直接关于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]);
        }
    }])
}]);

要逐字使用此代码,请指定&#39; lib&#39;作为您应用的依赖。

致记:

答案 3 :(得分: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. */
}

答案 4 :(得分: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!

答案 5 :(得分:1)

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

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

Sean修正负数的关键见解是!!如果你正在进行正向排序,请使用'!'+谓词;如果你正在进行反向排序,请使用'!!'+谓词。

下面的代码段演示了这一点。顺便说一句,我已经设置了谓词(选择propery进行排序)和反转内部对象(“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>

答案 6 :(得分: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);
        }
    };
});

答案 7 :(得分:0)

我不知道为什么其他答案建议将空值记录置于底部,如果我想要正常排序,则表示在ASC顺序中所有空顶部和DESC顺序所有空值都归结为底部,我在这里尝试了其他答案,但无法帮助我,所以更改代码将null转换为&#39;&#39;在我的数组中它现在像这样顺利运行:

$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;
}

答案 8 :(得分: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