AngularJS orderBy Function без сортировки

Я пытаюсь использовать пользовательскую функцию orderBy. Первоначально я хочу, чтобы данные отображались в том порядке, в котором они были добавлены в $scope.rows, и только после нажатия на заголовок столбца они должны упорядочиваться по определенному свойству. Вот моя скрипка:

http://jsfiddle.net/S8M4c/

Вот мой взгляд:

<table ng-app ng-controller="ctrl">
    <tr>
        <th><a ng-click="orderBy = 'id'">ID</a></th>
        <th><a ng-click="orderBy = 'name'">Name</a></th>
    </tr>
    <tr ng-repeat="row in rows | orderBy:mySort">
        <td>{{row.object.id}}</td>
        <td>{{row.object.name}}</td>
    </tr>
</table>

Вот мой контроллер:

function ctrl($scope)
{
    // Initially, we don't sort by anything
    $scope.orderBy = "";
    $scope.rows = [];

    // Add some rows
    for(var i = 10;i < 30;i++)
    {
        $scope.rows.push({settings: {foo: true}, object: {id: i, name: "Name " + i}})   
    };

    $scope.mySort = function(row)
    {
        if($scope.orderBy != "")
        {
            return row.object[$scope.orderBy];
        }

        // What do I return here??
        return "";
    }
}

В случае, если $scope.orderBy не задано и я хочу вернуть $scope.rows в исходном порядке, что мне вернуть в $scope.mySort? Я не могу return row.object.id, потому что не гарантируется, что строки будут добавлены в порядке их идентификатора. Запустив мой код в Chrome 32, первая строка, которая появляется, имеет идентификатор 20, что является промежуточной строкой.


person Dave    schedule 30.01.2014    source источник
comment
Просто предположение: return row.object.id ?   -  person DCoder    schedule 30.01.2014
comment
Дело в том, что в моем реальном приложении строки не обязательно добавляются в порядке их идентификатора. На самом деле, они могут (кажется) быть полностью несортированными при первой загрузке, что желательно. Я обновил свой вопрос, чтобы отразить это.   -  person Dave    schedule 30.01.2014
comment
Тогда лучше всего, вероятно, добавить новое свойство к каждому объекту — это свойство должно представлять постоянно растущий индекс, используемый для этой сортировки.   -  person DCoder    schedule 30.01.2014
comment
К сожалению, я не могу добавить свойства к своему объекту, потому что он привязан к socketIO и Redis. Сам объект не имеет понятия о том, что он находится в объекте строки. Вот почему я надеюсь, что есть способ сохранить естественный порядок строк, когда я использую пользовательскую функцию orderBy.   -  person Dave    schedule 30.01.2014


Ответы (3)


Я думаю, вам нужно написать свою собственную функцию sortby. Оригинальный angulars orderBy — это обычный фильтр, возвращающий отсортированный массив. Ваш фильтр может выглядеть примерно так:

.filter('mySort', function(){
    return function(values, param){
        if(param===''){
            return values;
        }else{
             // very important! create a copy of the array - otherwise 
             // the $wtachCollection function will fire to often!
             var arrayCopy = [];
             for ( var i = 0; i < values.length; i++) { arrayCopy.push(values[i]); }

            return arrayCopy.sort(function(a,b){
                var v1 = a.object[param];
                var v2 = b.object[param];
                // you know best how to sort it!
                if (v1 === v2) return 0;
                return v1 < v2 ? -1 : 1;
            });   
        }
    }
})

Вы можете использовать этот фильтр следующим образом:

<table ng-app="myApp" ng-controller="ctrl">
    <tr>
        <th><a ng-click="orderBy = 'id'">ID</a></th>
        <th><a ng-click="orderBy = 'name'">Name</a></th>
    </tr>
    <tr ng-repeat="row in rows | mySort:orderBy">
        <td>{{row.object.id}}</td>
        <td>{{row.object.name}}</td>
    </tr>
</table>

вот ваша измененная скрипта: http://jsfiddle.net/spRf6/ я немного изменил имена так что вы можете видеть, что сортировка работает.

person michael    schedule 30.01.2014

return $scope.rows.indexOf(row);

(Fiddle.)

Вы также можете сделать это с готовым orderBy, предоставив функцию, возвращающую это как предикат по умолчанию:

Контроллер:

$scope.mySort = $scope.unsorted = function(row)
    {
        return $scope.rows.indexOf(row);
    }

Вид:

<div ng-app ng-controller="ctrl">
    <table>
        <tr>
            <th><a ng-click="mySort = 'object.id'">ID</a></th>
            <th><a ng-click="mySort = 'object.name'">Name</a></th>
        </tr>
        <tr ng-repeat="row in rows | orderBy:mySort">
            <td>{{row.object.id}}</td>
            <td>{{row.object.name}}</td>
        </tr>
    </table>
    <button ng-click="mySort = unsorted;">Original Sort</button>
</div>

Поиграйте здесь (я изменил числа, используемые в объектах, чтобы сортировать по идентификатору, сортировать по имя и исходная сортировка не совпадают.)

person molgin    schedule 24.04.2015

Создайте копию массива объектов, и порядок станет тривиальным:

Контроллер:

$scope.objects = [];

angular.forEach($scope.rows, function(row){
    $scope.objects.push(row.object);
});

Вид:

<tr ng-repeat="object in objects | orderBy:orderBy">
    <td>{{object.id}}</td>
    <td>{{object.name}}</td>
</tr>

Нет необходимости в функции mySort.

person Gruff Bunny    schedule 30.01.2014
comment
Честно говоря, это, вероятно, ответ в большинстве случаев. Однако в моей конкретной ситуации мне нужно сохранить объект как свойство строки, потому что он нужен в другом месте. Спасибо хоть! - person Dave; 31.01.2014
comment
Это все еще так. Массив объектов содержит только ссылки на исходные объекты. - person Gruff Bunny; 31.01.2014