javascript - уроки - angularjs на русском



AngularJS orderby с пустым полем (6)

Я заказываю свои данные и выполняю все исправления, кроме некоторых полей, пустых или не имеющих значения. При заказе эти пустые поля появляются в первую очередь. Например, при заказе номеров мы получим огромный пустой список до получения значений «0».

Я делаю это так:

ng-click="predicate = 'name'; reverse=!reverse"

а также

ng-repeat="name in names | orderBy:predicate:reverse"

JSFiddle: http://jsfiddle.net/JZuCX/1/

Есть ли простой элегантный способ исправить это? Я хочу, чтобы пустые поля стали последними, несмотря ни на что.

https://src-bin.com


Answer #1

Сортировка и обратная сортировка с использованием столбца сортировки переменных и сохранение неопределенного внизу, даже ниже отрицательных значений

Мне нравится элегантность ответа Шона выше! Мне нужно было дать моим пользователям возможность выбрать столбец для сортировки и выбор направления сортировки, но все же нужно, чтобы undefined упал на дно, даже если есть отрицательные числа.

Ключевое понимание Шона, фиксирующего отрицательные числа, есть !!. Используйте префикс «!» +, Если вы выполняете сортировку вперед и «!!» + предикат, если вы делаете обратную сортировку.

Ниже приведен фрагмент ниже. Кстати, я поставил переменные, которые устанавливают предикат (выбор свойства для сортировки) и обратный внутри объекта («d»), так что мы не получаем странных проблем с областью. Вам может не понадобиться «d» в вашей среде.

Более того, вы, вероятно, захотите использовать что-то лучше, чем мои дерьмовые кнопки внизу страницы, чтобы управлять вашим предикатом и направлением. Однако это позволяет легко читать ключевые части кода.

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>


Answer #2

Здесь! : D

Это решение расширяет нормальную функциональность углового фильтра orderBy чтобы принять третий аргумент, определяющий, следует ли инвертировать обычную сортировку нулевых и неопределенных значений. Он отслеживает имена свойств, которые он передал (не только один), и не перебирает элементы в секунду, как это делают некоторые другие решения. Он используется следующим образом:

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

Я нашел кучу нитей, некоторые из них не напрямую orderBy , и скомпилировали их методы, а также пару моих собственных:

angular.module('lib')
.config(['$provide', function ($provide) {
    $provide.decorator('orderByFilter', ['$delegate', '$parse', function ($delegate, $parse) {
        return function () {
            var predicates = arguments[1];
            var invertEmpties = arguments[3];
            if (angular.isDefined(invertEmpties)) {
                if (!angular.isArray(predicates)) {
                    predicates = [predicates];
                }
                var newPredicates = [];
                angular.forEach(predicates, function (predicate) {
                    if (angular.isString(predicate)) {
                        var trimmed = predicate;
                        if (trimmed.charAt(0) == '-') {
                            trimmed = trimmed.slice(1);
                        }
                        var keyFn = $parse(trimmed);
                        newPredicates.push(function (item) {
                            var value = keyFn(item);
                            return (angular.isDefined(value) && value != null) == invertEmpties;
                        })
                    }
                    newPredicates.push(predicate);
                });
                predicates = newPredicates;
            }
            return $delegate(arguments[0], predicates, arguments[2]);
        }
    }])
}]);

Чтобы использовать этот код дословно, укажите «lib» в качестве зависимости для вашего приложения.

Кредиты для:

  • $parse
  • [nullSorter].concat(originalPredicates)
  • узор decorator

Answer #3

В дополнение к решению Klaster_1 добавьте дополнительный параметр, чтобы сделать фильтр более общим:

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

Реализация

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

Фильтр

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


Answer #4

Как насчет этого для сортировки строк:

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

Преимущество (кроме краткости) состоит в том, что он сортирует null & undefined с пустыми строками.

В моем случае я хотел, чтобы пробелы & nulls & undefineds вместе вверху (nulls и undefineds по умолчанию сортируют снизу), поэтому я использовал:

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

Answer #5

Я не верю, что для этого есть решение «из коробки». Я легко ошибаюсь. Вот моя попытка решения с использованием функции в качестве предиката:

ng-repeat="name in names | orderBy:predicate"

Внутри вашего контроллера:

$scope.predicate = function(name) {
    return name === '' ? 'zzzzzzz' : !name; 
    /* The 'zzzzzz' forces the empty names to the end, 
      I can't think of a simpler way at the moment. */
}

Answer #6

Я не знаю, почему другой ответ предлагает помещать записи нулевого значения внизу. Если я хочу нормально сортировать, значит, в ASC-порядке все нулевые сверху и в порядке DESC все нули идут вниз, я пробовал другие ответы здесь, но не помог мне изменить код, чтобы преобразовать значение null в '' в моем массиве, и теперь он работает так гладко:

$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;
}




angularjs