Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I replace an object in array that is displayed using ng-repeat?

I have an array of items that is displayed in a table using ng-repeat. When you click on an item, that item is pulled from the server and the table should then be updated with the updated item.

Function to get the updated item when clicking on an item in the table:

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

I'm displaying the items using:

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

The problem: The item in the table is never updated.

What's the best way to update the item in the ng-repeat? Can i use "track by $index" in the ng-repeat for this? Or do I have to iterate over myItems to find the item I want to replace?

Update:

A possible solution is instead of using

item = updatedItem,

to use:

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

However, I feel that there should be a "cleaner" way of doing this.

like image 532
gusjap Avatar asked Apr 29 '15 14:04

gusjap


3 Answers

There isn't a much cleaner way (then your update). As you noticed, when you change item in your callback function you change the local reference, and not the original item in the array.

You can improve this a bit by using the $index from the ng-repeat, instead of calculating it yourself:

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

And in your controller:

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

You can also use angular.copy instead but it's much less efficient:

function(updatedItem){
    angular.copy(updateItem, item);
},
like image 182
eladcon Avatar answered Oct 21 '22 16:10

eladcon


If I understand your problem properly

could something like this work?

<!-- 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;
    });
};
like image 20
Eloims Avatar answered Oct 21 '22 17:10

Eloims


item may start as a reference to an item in your list, but when you say:

item = updatedItem;

You reseat that binding -- you are no longer referring to the item in the list, but to the disconnected one that was returned in your promise. Either you will need to modify the item, like so:

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

Or, if it gets too hairy, you might consider an item array that looks more like this:

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

At which point your update function will look like this:

function(updatedItem){
    item.data = updatedItem;
},
like image 1
Michael Hays Avatar answered Oct 21 '22 16:10

Michael Hays