HMdeveloper
HMdeveloper

Reputation: 2884

ng-repeat does not get updated

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

Answers (3)

Troels Larsen
Troels Larsen

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

Dave
Dave

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

eliagentili
eliagentili

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

Related Questions