web-dev-qa-db-fra.com

Comment puis-je remplacer un objet dans un tableau affiché à l'aide de ng-repeat?

J'ai un tableau d'éléments qui est affiché dans une table en utilisant ng-repeat. Lorsque vous cliquez sur un élément, cet élément est extrait du serveur et la table doit ensuite être mise à jour avec l'élément mis à jour.

Fonction pour obtenir l'élément mis à jour en cliquant sur un élément de la table:

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

J'affiche les éléments en utilisant:

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

Le problème: l'élément de la table n'est jamais mis à jour.

Quel est le meilleur moyen de mettre à jour l'élément dans le ng-repeat? Puis-je utiliser "track by $ index" dans le ng-repeat pour cela? Ou dois-je parcourir mes éléments pour trouver l'élément que je souhaite remplacer?

Mettre à jour:

Une solution possible est au lieu d'utiliser 

item = updatedItem,

utiliser:

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

Cependant, j'estime qu'il devrait y avoir une façon "plus propre" de procéder.

15
gusper

Comme vous l'avez remarqué, lorsque vous modifiez la variable item dans votre fonction de rappel, vous modifiez la référence locale et non l'élément d'origine du tableau.

Vous pouvez un peu améliorer cela en utilisant le $index à partir du ng-repeat, au lieu de le calculer vous-même:

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

Et dans votre contrôleur:

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

Vous pouvez aussi utiliser angular.copy à la place mais c'est beaucoup moins efficace:

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

Si je comprends bien votre problème

quelque chose comme ça pourrait-il fonctionner?

<!-- 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 peut commencer comme référence à un élément de votre liste, mais lorsque vous dites:

item = updatedItem;

Vous remettez en place cette liaison - vous ne faites plus référence à l'élément de la liste, mais à l'élément déconnecté qui a été renvoyé dans votre promesse. Soit vous devrez modifier l’article, comme ceci:

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

Ou, si cela devient trop poilu, vous pourriez envisager un tableau d'éléments qui ressemble davantage à ceci:

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

A quel point votre fonction de mise à jour ressemblera à ceci:

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

Je viens de passer des heures sur cette question. Je ne pouvais pas utiliser la solution $index de @eladcon, car mon ng-repeat utilisait également un filtre; l'index n'est pas correct si les lignes/éléments sont filtrés.

Je pensais pouvoir faire ceci:

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

mais ça ne marche pas.

J'ai fini par itérer le tableau jusqu'à trouver une correspondance, puis à l'aide du $index de l'itération (et non du ng-repeat) pour définir l'élément de tableau sur le nouvel élément.

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

Voir ici: https://codepen.io/anon/pen/NpVwoq?editors=0011

0
Sean