4

I need to take records with null values on top , when I'm sorting by ASC

<tr ng-repeat="footballer in footballers=(footballers | orderBy:predicate)">
predicate : ['team.name','id]

Some footballers have no team, so team object == null and team.name==null, and I need to have them on the top

I wanted to rewrite sort function, but I need to save predicate

4 Answers 4

8

You can use something like this in your controller:

$scope.nullsToTop = function(obj) {
  return (angular.isDefined(obj.team) ? 0 : -1);
};

And on the HTML:

<tr ng-repeat="footballer in footballers | orderBy:[nullsToTop].concat(predicate)">

This way you can maintain your predicate separately. Just concat the nullsToTop function in the orderBy expression to run it first.

Plunker

Sign up to request clarification or add additional context in comments.

3 Comments

thanks a lot! but there is one moment : I used function isDefined and it returns true,when object isn't undefined. So i used isObject and it helped me!
How can I do that using the $filter service?
@artdias90 i had the same issue & posted how i solved it below
1

Create a function in the controller that will receive as parameter the entity and will return either ['team.name','id] either [] or other values that will help push the non-sortable elements to top/bottom of the list.

EDIT (example)

HTML:

<li ng-repeat="item in items | orderBy:getItemOrder track by $index">...

AngularJS Ctrl:

$scope.getItemOrder = function (entity) {
  if (entity.id === null || .... === null) {
    return 0;
  }

  return ['team.name','id];
}

1 Comment

can you write the example of this function? what i need to do? i tried to rewrite sort function like this : $scope.nullSortFunction = function () { return function (footballer) { if (footballer.team === null) { footballer.team = {}; footballer.team.name = ''; } } };
1

I was able to do it by returning a '+' or a '-' if the value is null, close to what bmleite did but is more contained in the function itself.

1. create a function that adds a + or a - to the null values depending on the sort order (asc or desc) so that they'd always remain at either the top or bottom

    function compareAndExcludeNull(element){
        var compareWith = $scope.order.propertyName; // in your case that's 'predicate'

        var operatorToBottom = $scope.order.reverse ? '+' : '-'; // If decending then consider the null values as smallest, if ascending then consider them biggest
        var operatorToTop = $scope.order.reverse ? '-' : '+';

        if(element[compareWith] == null){
            return operatorToTop;
        } else {
            return operatorToBottom+element[compareWith];
        }
    }

if you want to have the null values at the bottom of the sorted array then just switch the operatorToTop with operatorToBottom and vice versa to get:

    function compareAndExcludeNull(element){
        var compareWith = $scope.order.propertyName; // in your case that's '

        var operatorToBottom = $scope.order.reverse ? '+' : '-'; // If decending then consider the null values as smallest, if ascending then consider them biggest
        var operatorToTop = $scope.order.reverse ? '-' : '+';

        if(element[compareWith] == null){
            return operatorToBottom;
        } else {
            return operatorToTop+element[compareWith];
        }
    }

2. Call the function and pass the array you're sorting

Javascript:

In my case I am calling this function from HTML and passing different propertyName depending on the column the user is sorting by, in your case you'd just need to pass 'predicate' as the propertyName

    $scope.order.sortBy = function(propertyName){
        $scope.order.reverse = (propertyName !== null && $scope.order.propertyName === propertyName) ? !$scope.order.reverse : false;
        $scope.order.propertyName = propertyName;
        $scope.resources = $filter('orderBy')($scope.resources,compareAndExcludeNull,$scope.order.reverse);
    };

HTML:

<div>
    <span ng-if="showKeywords" class="label label-info" ng-click="order.sortBy('keyword')" style="margin-right: 5px">
        Order by Keywords
        <span ng-if="order.propertyName=='keyword'" class="glyphicon glyphicon-triangle-{{order.reverse? 'bottom' : 'top'}}">
        </span>
    </span>
    <span ng-if="showWebsites" class="label label-info" ng-click="order.sortBy('res_title')">
        Order by Website
        <span ng-if="order.propertyName=='res_title'" class="glyphicon glyphicon-triangle-{{order.reverse? 'bottom' : 'top'}}">
        </span>
    </span>
</div>

Comments

1

I know this is an old post but there is a better way for doing this and could not see it anywhere.

var myApp = angular.module('myApp', []);

myApp.controller('myCtrl', ["$scope", function($scope){
  $scope.footballers = [
        {id: 0, qt: 13},
        {id: 1, qt: 2},
        {id: 2, qt: 124},
        {id: 3, qt: 12125},
        {id: null , qt: 122},
        {id: 4, qt: -124},
        {id: 5, qt: -5235},
        {id: 6, qt: 43},
        ]
}]) 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>


<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="footballer in footballers | orderBy:['id==null || id']">
    {{footballer.id}}, {{footballer.qt}}
</div>
</div>

One can also use this to show 'id' with any specific value on top of others

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.