Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ng-repeat not updating on update of array

Tags:

angularjs

I'm rendering data through an ng-repeat cycle. And i would like it to update as I update the array. From what i read this should happen automatically however this is not working. So what am i doing wrong?

html:

<tr ng-repeat="data in dataDifferenceArray">     <td>       {{data.name}}     </td>     <td>       {{data.startData}}     </td>     <td>       {{data.endData}}     </td>     <td>       {{data.differenceData}}     </td> </tr> 

Controller (this function is triggered on a button with ng-click):

$scope.getDifferences = function () {   $scope.dataDifferenceArray = [];   var i;   for (i = 0; i < 20 ;i++) {     $scope.dataDifferenceArray.push({       name : 30,       startData : 20,       endData : 2,       differenceData : 30     })   } } 

Console.log reveals that the array is updated correctly, however the table in my view does not change. I don't know what i'm doing wrong.

like image 924
Mischa Avatar asked Apr 24 '15 13:04

Mischa


People also ask

Does ng-repeat create a new scope?

Directives that Create Scopes In most cases, directives and scopes interact but do not create new instances of scope. However, some directives, such as ng-controller and ng-repeat, create new child scopes and attach the child scope to the corresponding DOM element.

How do I get the index of an element in NG-repeat?

Note: The $index variable is used to get the Index of the Row created by ng-repeat directive. Each row of the HTML Table consists of a Button which has been assigned ng-click directive. The $index variable is passed as parameter to the GetRowIndex function.

Where is the last element in NG-repeat?

You can use $last variable within ng-repeat directive. Take a look at doc. Where computeCssClass is function of controller which takes sole argument and returns 'last' or null .

How do you use NG-repeat in a table?

Definition and UsageThe ng-repeat directive repeats a set of HTML, a given number of times. The set of HTML will be repeated once per item in a collection. The collection must be an array or an object. Note: Each instance of the repetition is given its own scope, which consist of the current item.


1 Answers

That's because you change the array reference in your method getDifferences.

To avoid that, us dot, for example with "controller as" syntax:

<div ng-controller="myController as c">     [...]      <tr ng-repeat="data in c.dataDifferenceArray">         <td>           {{data.name}}         </td>         <td>           {{data.startData}}         </td>         <td>           {{data.endData}}         </td>         <td>           {{data.differenceData}}         </td>     </tr>     [...] 

If you want to understand how scopes work, i would advice this article : https://github.com/angular/angular.js/wiki/Understanding-Scopes#ngRepeat

Another solution could be :

$scope.getDifferences = function () {   $scope.dataDifferenceArray.length = 0; // here ----   var i;   for (i = 0; i < 20 ;i++) {     $scope.dataDifferenceArray.push({       name : 30,       startData : 20,       endData : 2,       differenceData : 30     })   } } 

but in this solution, you need to create the array outside (and only once) : $scope.dataDifferenceArray = [];

Edit2: My answer was not really clear, let's try to understand what is happening in deep:

Q: Why does the ng-repeat still has the reference REFERENCE1 ?

You have to remember that there is not only 1 scope in your template.

Eg: the ng-repeat directive create new scopes for each of the repeated elements, but we can still access to the parent scope in each child scope. Angular implemented this behavior using Prototype Inheritance: each child scope inherit the properties of its parent scope thanks to its prototype.

You can experiment how it is working by inspecting one on your child elements, then enter in the console: $($0).scope() (it will give you the scope of the selected element, $0 is the selected element (Chrome)). You can now see that there is the same object in $($0).scope().$parent and $($0).scope().__proto__, it is your parent scope.

But there is one problem with prototype inheritance: Let's say we have A = {}; B = {C: 1}, if A inherits from B then A.C == 1. But if we affect a new value A.C = 2, we did not change B, only A.

Angular expressions are evaluated using the current scope as this. So if we have something like ng-click="dataDifferenceArray = []" it is equivalent to this.dataDifferenceArray = [] with this being the scope of the element where ng-click is.

This problem is solved when you are using controller-as because it injects the controller in the scope and you will never directly affect a property to the scope.

Let's take back our example: A = {}; B = {C: {D: 1}}, if A inherits from B then A.C.D == 1. And now even if we affect a new value A.C.D = 2, we changed B also.

like image 161
antoinestv Avatar answered Sep 20 '22 14:09

antoinestv