AngularJS - orderBy对象的多个参数,并将null属性移动到每个参数的末尾

时间:2015-09-07 10:33:06

标签: angularjs angularjs-orderby

我需要对一个对象数组进行排序,但问题是如果对象的某些属性是null

实施例

[   
    {
        "foo": 2,
        "bar": 1
    },
    {
        "foo": null,
        "bar": 1
    },
    {
        "foo": 1,
        "bar" : 2
    }
]

如果我使用orderBy:['foo','bar']我得到

[   
    {
        "foo": null,
        "bar": 1
    },
    {
        "foo": 1,
        "bar" : 2
    },
    {
        "foo": 2,
        "bar": 1
    }
]

但我想得到的是这个

[   
    {
        "foo": 1,
        "bar" : 2
    },
    {
        "foo": null,
        "bar": 1
    },
    {
        "foo": 2,
        "bar": 1
    }
]

因此,按字母顺序,我希望null追求“z”

2 个答案:

答案 0 :(得分:0)

要更改常规排序行为,您需要实现自己的排序器:

HTML:

<div ng-app="myapp">
  <ul ng-controller="MyCtrl">
    <li ng-repeat="item in items | myOrderBy:['foo', 'bar']">{{item}}</li>
  </ul>
</div>

JS:

app.filter("myOrderBy", function () {
  return function (input, sortOrder) {
    return input.sort(function (a, b) {
      var order;
      for (var i = 0; i < sortOrder.length; i++) {
        order = sortOrder[i];
        if (a[order] !== b[order]) {
          break;
        }
      }

      // make null being ordered last
      if (a[order] === null && b[order] !== null) {
        return 1;
      }
      if (b[order] === null && a[order] !== null) {
        return -1;
      }

      // I am assuming you want to treat integers as strings
      if ("" + a[order] < "" + b[order]) {
        return -1;
      }
      if ("" + a[order] > "" + b[order]) {
        return 1;
      }

      // values are equal
      return 0;
    });
  };
});

工作示例:http://codepen.io/cgav/pen/GpJoaB?editors=101

答案 1 :(得分:0)

通过@ccg添加答案:

为了处理排序中的嵌套属性(即[&#39; foo.bar&#39;]),我修改了他的答案。

(function () {
    angular.module('app')
    .filter('nullsFirst', nullsFirst);

    function nullsFirst () {
        return function (input, sortOrder) {
            return input.sort(function (a, b) {
                var compA;
                var compB;
                for (var i = 0; i < sortOrder.length; i++) {
                    // check for nested properties
                    if (sortOrder[i].indexOf('.') !== -1) {
                        var order = sortOrder[i].split('.');

                        compA = a;
                        compB = b;

                        order.forEach(function (prop) {
                            if (compA != null) {
                                compA = compA[prop];
                            }
                            if (compB != null) {
                                compB = compB[prop];
                            }
                        });
                    } else {
                        compA = a[sortOrder[i]];
                        compB = b[sortOrder[i]];
                    }

                    if (compA !== compB) {
                        break;
                    }
                }

                // make null being ordered first
                if (compA == null && compB != null) {
                    return 1;
                }
                if (compB == null && compA != null) {
                    return -1;
                }

                // I am assuming you want to treat integers as strings
                if ('' + compA < '' + compB) {
                    return -1;
                }
                if ('' + compA > '' + compB) {
                    return 1;
                }

                // values are equal
                return 0;
            });
        }
    };
})();

此添加对于您的特定问题不是必需的,但可以为将来的某个人提供更完整的解决方案。感谢@ccg的主要部分。