2013-04-20 2 views
79

Я новичок в 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); 
    } 

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

Спасибо!

ответ

128

Вместо или ретрансляции на $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); 
} 
+0

Ничего себе, это работает отлично! – FuzzBuzz

+1

@ pkozlowski.opensource Вы гений! Вы можете передать предмет, а не индекс .. Wow !! Спасибо чувак. –

+0

Array indexOf недоступен в Internet Explorer 8 и ниже. –

3

Попробуйте это:

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

} 

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

+0

Хотел бы проголосовать за ответ только для ссылок, если бы мог. – ankr

18

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

Я решить мою проблему с пользовательским фильтром:

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 (имя настраивается) в каждый объект коллекция.

+0

Не могли бы вы объяснить, почему другие ответы не подходят для вашей ситуации? –

+1

@ pkozlowski.opensource Это намного чище. Также в зависимости от того, какие события могут быть присоединены, и сложность элементов в indexOf намного эффективнее. Также '$ scope.items.splice ($ scope.items.indexOf (item), 1);' не будет работать так, как ожидалось, для повторяющихся элементов. – martin

+1

@martin вы должны резервировать свои претензии относительно производительности с реальными числами. У фильтра есть _huge_ недостаток выполнения в цикле _each и every_ $ digest, поэтому я не думаю, что это помогает в производительности ... –

1

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

Решение «миля» - это именно то, что мне тоже нужно. Ответить на pkozlowski.вопрос с открытым исходным кодом: когда у вас есть либо вложенный ngRepeat s, либо динамический список (например, когда вы разрешаете удаление), либо оба (это мой случай), использование $index не работает, потому что это будет неправильный индекс для внутренних данных после сортировка и использование 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); 
    }); 
}) 
15

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

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

Это лучше всего и так просто, а не создание настраиваемого фильтра и т. д. +1 –

+0

как это не правильный ответ? Это решило мою проблему –

-2

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

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

Смотрите мой ответ here.

Смежные вопросы