angularjs orderBy有多个函数,如何反转?

mik*_*kec 7 angularjs

我有一个ng-repeat迭代一组对象,需要一些函数来提取我想要排序的值.

我的ng-repeat看起来像这样:

ng-repeat="row in rows | orderBy: [sortFnOne, sortFnTwo, ...]"
Run Code Online (Sandbox Code Playgroud)

我遇到麻烦的是,我希望sortFnOne被颠倒过来.这些是提取我无法使用简单属性访问的字符串,因为它正在对数据进行一些转换以生成我尝试排序的这些值.

如果它很简单,我知道我会这样做:

ng-repeat="row in rows | orderBy: ['-id', 'name', '-status', ...]"
Run Code Online (Sandbox Code Playgroud)

如果这些功能只是返回布尔我可以!获取我想要的结果的返回值,但其中一些是返回字符串,有些是以YYYY-MM-DD格式返回日期.

Jon*_*son 0

我自己也遇到过这个限制......没有办法用过滤器反转函数完成的排序orderBy

据我所知,在原生 JavaScript API 中,没有简单的方法可以重现这种带方向的复合排序(按“A”升序排列,然后按“B”降序排列)。

Array.prototype.sort通过比较函数提供基本排序(有关详细信息,请参阅MDN 文档),但无法在不编写另一个比较函数的情况下轻松切换排序顺序(反向),并且它不提供复合排序的解决方案。我们需要的是一个紧凑的符号来指定多个排序的方向和优先级。

我不久前写了这个助手来帮助解决这个问题。

  var orderByAgeThenName = new OrderByBuilder().asc(getAge).asc(getName).build();
  var friendsByAgeThenName = orderByAgeThenName(friends);

  var orderByNameThenAge = new OrderByBuilder().desc(getName).asc(getAge).build();
  var friendsByNameThenAge = orderByNameThenAge(friends);
Run Code Online (Sandbox Code Playgroud)

这不是角度过滤器,因此只需将其包装在控制器方法中并从模板中调用它即可。或者,只需将顺序应用于控制器内的数组。

我想这可以适应角度过滤器......

可运行示例:

  var orderByAgeThenName = new OrderByBuilder().asc(getAge).asc(getName).build();
  var friendsByAgeThenName = orderByAgeThenName(friends);

  var orderByNameThenAge = new OrderByBuilder().desc(getName).asc(getAge).build();
  var friendsByNameThenAge = orderByNameThenAge(friends);
Run Code Online (Sandbox Code Playgroud)
angular.module('orderByExample', [])
.controller('ExampleController', ['$scope', function($scope) {
  var friends =
    [{name:'Jon', phone:'555-1212', age:10},
     {name:'Zach', phone:'555-2276', age:7},                     
     {name:'Zach', phone:'555-9876', age:19},
     {name:'Zach', phone:'555-9276', age:13},           
     {name:'Mike', phone:'555-4321', age:21},
     {name:'Adam', phone:'555-5678', age:35},
     {name:'Julie', phone:'555-8765', age:29}];

  function getName(f){
    return f.name;
  }

  function getAge(f){
    return f.age;
  }
  
  var orderByName       = new OrderByBuilder().desc(getName).build();
  var orderByNameAndAge = new OrderByBuilder().desc(getName).asc(getAge).build();

  $scope.friendLists = [
    {label:'Not Ordered', friends: friends},
    {label:'Name DESC', friends: orderByName(friends)},
    {label:'Name DESC, Age ASC', friends: orderByNameAndAge(friends)}
  ];
  
}]);




function OrderByBuilder(orderings){
  var _orderings = [];

  return {
    asc: function(fn){
      addOrdering(true,fn);
      return this;
    },
    desc: function(fn){
      addOrdering(false,fn);
      return this;
    },
    build: build
  };

  function addOrdering(asc,fn){
    _orderings.push({
      getterFn: fn,
      asc: asc
    });
    return this;
  }

  function build(){
    var compare = _orderings.reverse().reduce(function(nextComparer, ordering){
      return getComparerFn(ordering, nextComparer);
    },null);

    return function(xs){
      return xs.slice().sort(compare);
    };
  }

  // a comparerFn has the following signature:
  //		function(a: obj, b: obj): int

  function getComparerFn(ordering, nextComparer){
    var next = nextComparer || function(a,b){ return 0; };
    var getVal = ordering.getterFn;

    return function(a,b){
      var aVal = getVal(a);
      var bVal = getVal(b);
      if(aVal < bVal){ return ordering.asc ? -1 :  1; }
      if(aVal > bVal){ return ordering.asc ?  1 : -1; }
      return next(a,b);
    };
  }
}
Run Code Online (Sandbox Code Playgroud)