Reputation: 2884
I am struggling with a an issue that I have with angularjs and ng-repeat, I have a table which is generated by ng-repeat:
<div>
<select ng-model="item" ng-controller="dropdown"
ng-change="update(item)">
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
</select>
<table ng-controller="repeatTest">
<tr>
<td>name</td>
<td>family name</td>
<td>score</td>
</tr>
<tr ng-repeat="item in list">
<td>{{ item.name }}</td>
<td>{{ item.familyName }}</td>
<td>{{ item.score }}</td>
</tr>
</table>
</div>
and my js code is as follows:
var app = angular.module("myModule", []);
app.service('sharedService', function() {
this.list = [];
});
app.controller('dropdown', function($scope, sharedService) {
$scope.update = function(item) {
if (item == "volvo") {
sharedService.list = [ {
name : 'A',
familyName : 'AA',
score : '10'
}, {
name : 'B',
familyName : 'BB',
score : '5'
} ];
$scope.list = sharedService.list;
console.log($scope.list);
} else {
sharedService.list = [ {
name : 'zzz',
familyName : 'zzz',
score : '100'
}, {
name : 'zz',
familyName : 'zz',
score : '70'
} ];
$scope.list = sharedService.list;
}
}
});
app.controller('repeatTest', function($scope, sharedService) {
sharedService.list = [ {
name : 'xxx',
familyName : 'xxx',
score : 'xxx'
}, {
name : 'xx',
familyName : 'xx',
score : 'xx'
} ];
$scope.list = sharedService.list;
});
Now my problem is the table si generated at the page load and never change again when I change the select box though it should because I bind the table to the list which is defined in scope and I assume whenever scope changes table should be affected as well. Can anyone help?
Upvotes: 0
Views: 116
Reputation: 4651
You have two scopes, one for each controller. By assigning $scope.list you are in effect passing the list by reference to each controller. So you should either clean and recreate the array without reassigning $scope.list
or sharedService.list
, or you could:
Add
$scope.sharedService = sharedService;
on both controllers and use ng-repeat="item in sharedService.list"
instead, and you will get your updates.
The reason your current solution is not working is because you are creating a new array each time you call update. This means the other controller's list will still maintain a reference to the original/previous array.
An example of avoiding creating a new array each time:
var result = [];
if (item == "volvo") {
result = [ {
name : 'A',
familyName : 'AA',
score : '10'
}, {
name : 'B',
familyName : 'BB',
score : '5'
} ];
} else {
result = [ {
name : 'zzz',
familyName : 'zzz',
score : '100'
}, {
name : 'zz',
familyName : 'zz',
score : '70'
} ];
}
//Clear array
sharedService.list.splice(0,sharedService.list.length);
//Copy values from result into existing array
sharedService.list.push.apply(sharedService.list, result);
Please note this is untested. And you'd also have to do the initial assignment of $scope.list somewhere.
Upvotes: 1
Reputation: 4412
The 'repeatTest' controller doesn't have any way of knowing that the service data has changed... unless you tell it to watch for that. Try this version of that controller:
app.controller('repeatTest', function($scope, sharedService) {
$scope.list = sharedService.list;
$scope.$watch(function() {
return sharedService.list;
},
function(o, n) {
if (o != n) $scope.list = n
});
});
Also, since your dropdown controller doesn't directly affect the list in repeatTest, you don't need to update $scope.list in that controller:
app.controller('dropdown', function($scope, sharedService) {
$scope.update = function(item) {
console.log(item);
if (item == "volvo") {
sharedService.list = [{
name: 'A',
familyName: 'AA',
score: '10'
}, {
name: 'B',
familyName: 'BB',
score: '5'
}];
} else {
sharedService.list = [{
name: 'BMW',
familyName: 'Germany',
score: '100'
}, {
name: 'Frari',
familyName: 'America',
score: '100'
}];
}
}
// Do a little initialization
$scope.item="volvo";
$scope.update($scope.item);
});
Here's a plunk: http://plnkr.co/edit/42snC2WyfdKfNzrIKA0o
Upvotes: 1
Reputation: 619
You don't need two controllers for your example.
Just assign the dropdown controller to your parent div and remove the repeatTest controller. Something like this:
<div ng-controller="dropdown">
<select ng-model="item" ng-change="update(item)">
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
</select>
<table>
<tr>
<td>name</td>
<td>family name</td>
<td>score</td>
</tr>
<tr ng-repeat="item in list">
<td>{{ item.name }}</td>
<td>{{ item.familyName }}</td>
<td>{{ item.score }}</td>
</tr>
</table>
</div>
So, if you have the same controller for handling both select and table you don't need to watch the list variable in your services for changes.
You can solve in this way or implementing events, but i think this is the easily one.
Here a jsbin of the correct code: http://jsbin.com/sivapa/edit?html,js,console,output
Upvotes: 1