AngularJS orderby with empty field

前端 未结 9 1708
北海茫月
北海茫月 2020-12-05 13:19

I am ordering a my data and its working all correcty except some fields are empty or have no value. When ordered these empty field come up first. For example when ordering n

相关标签:
9条回答
  • 2020-12-05 13:44

    How about this for sorting strings:

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

    The advantage (apart from being more concise) is it sorts null & undefined with the blank strings.

    In my case I wanted the blanks & nulls & undefineds together at the top (nulls and undefineds by default sort to the bottom), so I used:

    item in (items|orderBy:['!!name', 'name'])
    
    0 讨论(0)
  • 2020-12-05 13:46

    Sorting, and reverse sorting, using a variable sort column, and keeping the undefined at the bottom, even below the negative values

    I love the elegance of Sean's answer above! I needed to give my users the ability to choose the column to sort on, and choice of sort direction, but still require the undefined's to fall to the bottom, even if there are negative numbers.

    The key insight from Sean that fixes negative numbers is !!. Use '!'+predicate if you are doing forward sorting and '!!'+predicate if you are doing reverse sorting.

    The snippet below demonstrates this. By the way, I have put the variables that set the predicate (choice of propery to sort on) and reverse inside an object ("d") just so that we don't get weird scope issues. You may not need the "d."s in your environment.

    Moreover you would probably want to use something better than my crappy buttons at the bottom of the page to control your sort predicate and direction. However this keeps the key parts of the code easy to read.

    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>

    0 讨论(0)
  • 2020-12-05 13:51

    In addition to the solution of Klaster_1, add an extra parameter to make the filter more generic:

    http://jsfiddle.net/Zukzuk/JZuCX/27/

    Implementation

    <tr ng-repeat="name in (names | orderBy:predicate:reverse | orderEmpty:'name':'toBottom')">
    

    Filter

    .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!

    0 讨论(0)
  • 2020-12-05 13:53

    I don't know why other answer suggest to put the null value records at the bottom, If I want to sort normally, means in ASC order all the null on top and in DESC order all the nulls go to bottom, I tried other answers here but could not helped me so change the code to convert the null to '' in my array and it works now smooth like this:

    $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;
    }
    
    0 讨论(0)
  • 2020-12-05 13:58

    I'd write a filter that takes items with empty name from ordered array and places them at the end:

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

    Code might look like this:

    .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.

    By the way, your fiddle doesn't contain any relevant code. Did you use the wrong link?

    Update 2: Your fiddle with my filter.

    0 讨论(0)
  • 2020-12-05 14:00

    @Klaster_1 was really on to something but as soon as I needed a nested value the filter stopped working. Also, if I was reverse ordering I still wanted my null values to show up before 0. I added $parse to take care of the nested keys and added a reverse parameter to I knew when to put the null values at the top.

    .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);
            }
        };
    });
    
    0 讨论(0)
提交回复
热议问题