Angularjs неправильний індекс $ після замовлення By


92

Я новачок у Angular.js і маю деякі проблеми з сортуванням масиву та роботою над цими відсортованими даними.

У мене є список з елементами, і я хочу відсортувати його за "Store.storeName", яке працює досі. Але після сортування даних моя функція delete вже не працює. Я думаю, це тому, що індекс $ неправильний після сортування, і тому неправильні дані видаляються.

Як я можу це вирішити? Впорядкування даних в області, а не у поданні? Як це зробити?

Ось відповідний код:

У поданні:

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

Це добре працює перед замовленням у поданні. Якщо чогось важливого не вистачає, будь ласка, дозвольте мені зараз.

Дякую!

Відповіді:


140

Замість того, щоб або переслати на $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);
}

1
@ pkozlowski.opensource Ви геній! Ви можете передати елемент, а не індексувати .. Ого !! Дякую людино.
good_evening

Масив indexOf недоступний в Internet Explorer 8 і старіших версіях.
Пітер Гедберг,

4
Заголовок питання задає неправильний індекс $ після orderBy, якого ця відповідь не стосується. Бувають випадки, коли вам потрібне правильне значення індексу $ (наприклад, shift shift у списку). Як отримати правильне значення індексу $ після того, як застосовано фільтр orderBy?
ClearCloud 8

Ви також можете створити новий масив із впорядкованого списку в шаблоні, виконавши щось на зразок цього: "ele in order_array = (array | filter: filter | orderBy: order_by)"
Porlune

Охайно! Дякую, брате.
CENT1PEDE

23

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

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

1
Це найкраще і настільки просто, а не створювати власні фільтри тощо. +1
Рафік Мохаммед

1
як це не правильна відповідь? Це вирішило мою проблему
Сайрус Зей

19

У мене була та сама проблема, і інші відповіді в цій темі не підходять для моєї ситуації.

Я вирішив свою проблему за допомогою спеціального фільтра:

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(ім'я можна налаштувати) до кожного об’єкта колекції.


Не могли б ви детальніше пояснити, чому інші відповіді не підходять для вашої ситуації?
pkozlowski.opensource

1
@ pkozlowski.opensource Це набагато чистіше. Також залежно від того, які події можуть бути прикріплені, та складності елементів у indexOf набагато ефективніше. Також $scope.items.splice($scope.items.indexOf(item),1);не буде працювати належним чином для дублікатів елементів.
Мартін

1
@martin, ви повинні підкріпити свої претензії щодо ефективності реальними цифрами. Фільтр має величезний недолік у тому, що він виконується на кожному циклі дайджесту $, тому я не думаю, що це допомагає з продуктивністю ...
pkozlowski.opensource

@ pkozlowski.opensource Це правда, і вона працює двічі для кожного циклу дайджесту $. Найголовніше - "залежно від того, які події можуть бути приєднані", продуктивність має значення, коли ви не маєте контролю за швидкістю, наприклад, непрограмована подія прокрутки - крайній випадок, я знаю.
Мартін

@mile Ну, у мене є дублікати, і це те, що я шукав, трохи сумно, що Angular не відстежує або оригінальний індекс у змінній $. я спробував, (key, item) in itemsі це теж не працює. (ключ не зберігається в оригіналі)
Rouche

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);

}

Ви можете знайти детальне пояснення у цьому записі в моєму блозі.


2

Якщо комусь потрібно скористатися $index, ви можете вказати ім'я відсортованому / відфільтрованому масиву:

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

Дивіться мою відповідь тут .


Я думаю, що ця відповідь чудова, якщо бракує деталей. Я думаю, що означає hmk, це те, що після відстоювання відфільтрованого списку, як вище, індекс можна використовувати проти нього (тобто "sortedItems [$ index]") для отримання потрібного запису.
Jeremythuff

1

Я б просто залишив коментар, але у мене немає "репутації".

рішення милі - це саме те, що мені теж потрібно було. Щоб відповісти на запитання pkozlowski.opensource: коли у вас є або вкладені ngRepeats, динамічний список (наприклад, де ви дозволяєте видалення), або обидва (що в моєму випадку), використання $indexне працює, оскільки це буде неправильний індекс для back-end дані після сортування та використання ngInitдля кешування значення також не працюють, оскільки вони не переоцінюються при зміні списку.

Зауважте, що рішення Mile дозволяє налаштувати ім’я властивості вкладеного індексу, передавши параметр <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 );
    });
})
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.