Angularjs неправильный $index после orderBy

Я новичок в Angular.js и имею некоторые проблемы, сортируя мой массив и работая над этими отсортированными данными.

У меня есть список с элементами и хочу, чтобы сортировать его по "Store.storeName", который работает до сих пор. Но после сортировки данных моя функция удаления больше не работает. Я думаю, это потому, что после сортировки индекс $неверен, и поэтому неверные данные удаляются.

Как я могу это решить? Заказ данных в области, а не в представлении? Как это сделать?

Вот какой код:

В представлении:

<tr ng-repeat="item in items | orderBy:'Store.storeName'">
                <td><input class="toggle" type="checkbox" ng-model="item.Completed"></td>
                <td>{{item.Name}}</td>
                <td>{{item.Quantity}} Stk.</td>
                <td>{{item.Price || 0 | number:2}} €</td>                
                <td>{{item.Quantity*item.Price|| 0 | number:2}} €</td>
                <td>{{item.Store.storeName}}</td> 
                <td><a><img src="img/delete.png" ng-click="removeItem($index)">{{$index}}</a></td>
            </tr>

И в моем контроллере у меня есть эта функция удаления, которая должна удалить определенные данные:

$scope.removeItem = function(index){
        $scope.items.splice(index,1);
    }

Это хорошо работает перед заказом в представлении. Если что-то важное отсутствует, позвольте мне сейчас.

Спасибо!

Ответ 1

Вместо или ретрансляции на $index, который, как вы заметили, будет указывать на индекс в отсортированном/отфильтрованном массиве, вы можете передать этот элемент непосредственно своей функции removeItem:

<a><img src="img/delete.png" ng-click="removeItem(item)">{{$index}}</a>

и измените функцию removeItem, чтобы найти индекс, используя метод indexOf массива следующим образом:

$scope.removeItem = function(item){
   $scope.items.splice($scope.items.indexOf(item),1);
}

Ответ 2

У меня была та же проблема, и другие ответы в этой теме не подходят для моей ситуации.

Я решил проблему с настраиваемым фильтром:

angular.module('utils', []).filter('index', function () {
    return function (array, index) {
        if (!index)
            index = 'index';
        for (var i = 0; i < array.length; ++i) {
            array[i][index] = i;
        }
        return array;
    };
});

который можно использовать следующим образом:

<tr ng-repeat="item in items | index | orderBy:'Store.storeName'">

а затем в HTML вы можете использовать item.index вместо $index.

Этот метод подходит для коллекций объектов.

Пожалуйста, учтите, что этот настраиваемый фильтр должен быть первым в списке всех примененных фильтров (orderBy и т.д.), и он добавит дополнительное свойство index (имя настраивается) в каждый объект Коллекция.

Ответ 3

Я начал изучать angular и столкнулся с подобной проблемой, и, основываясь на ответе @pkozlowski-opensource, я решил это просто с чем-то вроде

<a>
  <img src="img/delete.png" ng-click="removeItem(items.indexOf(item))">
  {{items.indexOf(item)}}
</a> 

Ответ 4

Попробуйте следующее:

$scope.remove = function(subtask) {

    var idx = $scope.subtasks.indexOf(subtask),
        st = $scope.currentTask.subtasks[idx];

    // remove from DB
    SubTask.remove({'subtaskId': subtask.id});

    // remove from local array
    $scope.subtasks.splice(idx,1);

}

В моем блоге вы можете найти подробное объяснение в этой записи.

Ответ 5

Я бы просто оставил комментарий, но у меня нет "репутации".

Решение

mile - это то, что мне тоже нужно. Чтобы ответить на вопрос pkozlowski.opensource: когда у вас есть либо вложенный ngRepeat s, динамический список (например, когда вы разрешаете удаление), либо оба (это мой случай), использование $index не работает, потому что это будет неправильно индекс для исходных данных после сортировки и использования ngInit для кэширования значения не работает либо потому, что он не переоценивается при изменении списка.

Обратите внимание, что решение "миля" позволяет настраивать имя свойства прикрепленного индекса, передавая параметр <tr ng-repeat="item in items | index:'originalPosition' | orderBy:'Store.storeName'">

Моя измененная версия:

.filter( 'repeatIndex', function repeatIndex()
{
// This filter must be called AFTER 'filter'ing 
//  and BEFORE 'orderBy' to be useful.
    return( function( array, index_name )
    {
        index_name = index_name || 'index';
        array.forEach( function( each, i )
        {each[ index_name ] = i;});
        return( array );
    });
})

Ответ 6

Если кому-то нужно использовать $index, вы можете указать имя в отсортированном/отфильтрованном массиве:

<tr ng-repeat="item in sortedItems = (items | orderBy:'Store.storeName') track by $index">

Смотрите мой ответ здесь.