Angularjs orderBy with multiple functions, how to cancel?

I have an ng repeat for a collection of objects that require some functions to retrieve the values ​​I want to sort.

My ng-repeat looks like this:

ng-repeat="row in rows | orderBy: [sortFnOne, sortFnTwo, ...]" 

What I ran into, I want sortFnOne to be canceled. This is retrieving strings that I cannot access using simple attributes, as it does some data conversion to create these values ​​that I am trying to sort.

If it were simple, I know that it is simple:

 ng-repeat="row in rows | orderBy: ['-id', 'name', '-status', ...]" 

If these functions simply returned booleans, I could simply! return value to get the result that I wanted, but some of them return strings, and some return dates in YYYY-MM-DD format.

+6
source share
2 answers

I myself came across this restriction ... there is no way to invert the ordering performed by the function with the orderBy filter.

As far as I can tell, there is no easy way to reproduce this type of compound ordering with direction (order in 'A' ascending, and descending B) in the native JavaScript API.

Array.prototype.sort offers a basic order using a comparison function (for more details see MDN docs ), but without the ability to easily switch the sort order (reverse) without writing another comparison function, it does not offer a solution for complex ordering. We need a compact notation indicating the direction and priority of several orders of magnitude.

I wrote this helper some time ago to help with this very problem.

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

This is not an angular filter, so just put it in the controller method and call it from your template. Or just apply the order in your array inside the controller.

I think this could be adapted to an angular filter ...

Runnable Sample:

 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); }; } } 
 <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.0-beta.6/angular.min.js"></script> <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css"> <div ng-app="orderByExample"> <div ng-controller="ExampleController"> <div class="row"> <div ng-repeat="friendList in friendLists" class="col-sm-4"> <h4>{{friendList.label}}</h4> <table class="table table-bordered table-condensed"> <tr> <th>Name</th> <th>Phone Number</th> <th>Age</th> </tr> <tr ng-repeat="friend in friendList.friends"> <td>{{friend.name}}</td> <td>{{friend.phone}}</td> <td>{{friend.age}}</td> </tr> </table> </div> </div> </div> </div> 
0
source

Angular allows you to provide a comparison function as the third argument to orderBy. This comparator function gives you the opportunity to indicate your own order.

Here is a Plunk that demonstrates dynamic complex sorting. It loads 100 entries from the JSON file and initially sorts the names first by name, then by name. When you sort something other than Last Name, it uses Last Name and First Name to break the links. However, while the sort order in the main field can be reversed, the example demonstrated will still sort the name and name in ascending order.

 $scope.compareData = function(left, right) { function compareValues(valueLeft, valueRight) { var valueReturn; if (!isNaN(parseInt(valueLeft)) && !isNaN(parseInt(valueRight))) { valueReturn = ((valueLeft * 1) < (valueRight * 1) ? -1 : ((valueLeft * 1) > (valueRight * 1) ? 1 : 0)); } else { valueReturn = valueLeft.toString().localeCompare(valueRight.toString()); } return valueReturn; } var dataReturn = 0; if (typeof right === "undefined") { dataReturn = 1; } else if (typeof left === "undefined") { dataReturn = -1; } else { var valuesLeft = left.value.split(","); var valuesRight = right.value.split(","); for (var i = 0; (i < valuesLeft.length) && (dataReturn === 0); ++i) { dataReturn = compareValues(valuesLeft[i], valuesRight[i]); dataReturn *= ($scope.sortReverse && (i > 0)) ? -1 : 1; } } return dataReturn; } 

Above was the function used for the comparator in linked Plunk. Note at the end that reversing sorting in a field is as simple as multiplying the result by -1.

0
source

Source: https://habr.com/ru/post/977441/


All Articles