it-swarm.com.ru

Как я могу заменить объект в массиве, который отображается с помощью ng-repeat?

У меня есть массив элементов, который отображается в таблице с помощью ng-repeat. Когда вы щелкаете по элементу, этот элемент извлекается с сервера, и таблица должна быть обновлена ​​обновленным элементом.

Функция для получения обновленного элемента при нажатии на элемент в таблице:

$scope.getUpdatedItem = function(item){
    itemService.getItem(item).then(
        function(updatedItem){
            item = updatedItem;
        },
        function(error){
            //Handle error
        }
    );
};

Я отображаю элементы, используя:

<tr ng-repeat="item in myItems">

Проблема: элемент в таблице никогда не обновляется.

Каков наилучший способ обновить элемент в ng-repeat? Могу ли я использовать для этого «track by $ index» в ng-repeat? Или мне нужно перебрать myItems, чтобы найти элемент, который я хочу заменить?

Обновление:

Возможное решение вместо использования 

item = updatedItem,

использовать:

var index = $scope.myItems.indexOf(item);
$scope.myItems[index] = updateItem;

Однако я чувствую, что должен быть «более чистый» способ сделать это.

15
gusper

Нет более чистого способа (тогда ваше обновление) . Как вы заметили, когда вы изменяете item в своей функции обратного вызова, вы изменяете локальную ссылку, а не исходный элемент в массиве.

Вы можете немного улучшить это, используя $index из ng-repeat вместо того, чтобы вычислять его самостоятельно:

<div ng-click="getUpdatedItem(item, $index)"> </div>

И в вашем контроллере:

$scope.getUpdatedItem = function(item, index){
    itemService.getItem(item).then(
    function(updatedItem){
        $scope.myItems[index] = updateItem;
    },
    function(error){
        //Handle error
    }
    );
};

Вместо этого вы также можете использовать angular.copy, но это гораздо менее эффективно:

function(updatedItem){
    angular.copy(updateItem, item);
},
14
eladcon

Если я правильно понимаю вашу проблему

может что-то вроде этой работы?

<!-- template code -->
<table>
    ...
    <tr ng-repeat="(index, item) in items">
        <td>{{item.name}}</td>
        <td>
             {{item.detail}}
             <button ng-if="!item.detail" ng-click="loadItem(index)">
        </td>
    </tr>
</table>

// Controller Code
$scope.items = [...]
$scope.loadItem = function(index){
    itemService.getItemDetail($scope.items[index]).then(function(itemDetail){
        $scope.items[index].detail = itemDetail;
    });
};
2
Eloims

item может начинаться как ссылка на элемент в вашем списке, но когда вы говорите:

item = updatedItem;

Вы повторно устанавливаете эту привязку - вы больше не ссылаетесь на элемент в списке, а на отключенный, который был возвращен в вашем обещании. Либо вам нужно будет изменить элемент, например так:

function(updatedItem){
  item.varA = updatedItem.varA
  item.varB = updatedItem.varB
  ...
}

Или, если он становится слишком волосатым, вы можете рассмотреть массив элементов, который выглядит примерно так:

var items = [ 
  { data: item1 },
  { data: item2 },
  { data: item3 }
};

В этот момент ваша функция обновления будет выглядеть так:

function(updatedItem){
    item.data = updatedItem;
},
1
Michael Hays

Я просто потратил часы на эту проблему. Я не мог использовать решение $index от @eladcon, так как мой ng-repeat также использовал фильтр, так как индекс не корректен, если строки/элементы фильтруются.

Я думал, что смогу просто сделать это:

$filter('filter')($scope.rows, {id: 1})[0] = newItem;

но это не работает.

Я закончил итерацию массива до тех пор, пока не нашел соответствие, а затем использовал $index из итерации (не из ng-repeat), чтобы установить элемент массива для нового элемента.

// i'm looking to replace/update where id = 1
angular.forEach($scope.rows, function(row, $index) {
  if (row.id === 1) {
    $scope.rows[$index] = newItem;
  }
})

Смотрите здесь: https://codepen.io/anon/pen/NpVwoq?editors=0011

0
Sean