I have an similar app as in the following example and I can't figure out why the source data is not updating. More info is in the example comments. I'm sure this is some trivial issue that I've overlooked.
Controller
$scope.items = [
{ id: 1, color: 'red', title: 'car' },
{ id: 2, color: 'blue', title: 'sky' },
{ id: 3, color: 'transparent', title: 'nothing' }
]
$scope.favoriteIds = [1, 2, 3]
$scope.getItem = function(id) { /* returns an item with given id */ }
Finally, there are two methods to modify $scope.items
, but only the first one works, because the new item gets not-already-known id.
$scope.changeData1 = function() {
$scope.items = [{ id: 666, color: 'ugly', title: 'face' }]
$scope.favoriteIds = [666]
}
$scope.changeData2 = function() {
$scope.items = [{ id: 1, color: 'ugly', title: 'face' }]
$scope.favoriteIds = [1]
}
View
<h1>Favourite items</h1>
<ul ng-repeat="id in favoriteIds" data-ng-init="item = getItem(id)">
<li>I like my {{ item.color }} {{ item.title }}</li>
</ul>
<button ng-click="changeData1()">Modify data</button>
<!-- prints: I like my ugly face -->
<button ng-click="changeData2()">Modify nothing</button>
<!-- prints: I like my red car -->
The problem is, that I need to use this second way to modify data.
I'm relatively new to Angular as well, so if there's a simple way to do this, I don't know what it is (unfortunately, Angular documentation is atrocious). Regardless, you can avoid this by rethinking the structure of your code (and you'll end up with a better program too).
In your view, you're using ng-init
to call getItem
on the id
during each iteration of your ng-repeat
loop. This is what's causing your problem, and it's (apparently) due to an Angular performance feature (more at this question).
Basically, don't use ng-init
except to execute something when your app starts. Otherwise, you'll end up with what you've got now: logic in the view (calling getItem(id)
) rather than the model, where it belongs.
Instead, use ng-repeat
to repeat over the exact data you want to display. Like I said before, this means some code rearrangement. For example, you could use a function to generate the user's current list of items on the fly. Check out this fiddle: http://jsfiddle.net/4pEpN/19/
See my comments in that code for all the changes I made, but the most relevant one is:
$scope.favoriteItems = function() {
var favObjs = [];
for (var i = 0; i < favoriteIds.length; ++i) {
favObjs.push(getItem(favoriteIds[i]));
}
return favObjs;
};
then in your view: <ul ng-repeat="item in favoriteItems()">
There are also lots of other approaches you could use. For instance, you could have an update
function, which handles anything that might need to be done after any user input (including updating the user's custom array of items). Then you could call this in your changeData
functions.