ng-init Used Twice Inside ng-repeat, Only First ng-init is Being Evaluated

See the below code:

<tr ng-repeat="x in [].constructor(6) track by $index" ng-init="loopNumber = $index">
    <td class="border-right" style="width:10%;" ng-init="day = monthOfData[7 * loopNumber]">
        <p>{{day}}</p>
    </td>
    <td class="border-right" style="width:10%;" ng-init="day = monthOfData[7 * loopNumber+1]">
        <p>{{day}}</p>
    </td>
</tr>

I expect where {{day}} is being used, the output would be something like:

1
2

However, the output is:

1
1

AngularJS seems to be skipping the second use of ng-init inside the ng-repeat. Is this a performance feature of AngularJS? I am using ng-init to save re-evulating the same expression.

Answer

This is not a bug, this usage of ng-init is wrong. To initialize means to set the start value of a variable, so with your last use of ng-init you’re initializing a variable that already has a value and “overwriting” what was already there.

In more detail: The first instance of ng-init sets loopNumber = 0 because arrays and indexes start with 0, not 1. Then you set day = 0 — at that point, both instances of {{day}} in your html would evaluate to 0. Then lastly you set day = 1, therefore the output of {{day}} becomes 1.

Note that this applies to all the places in your page where you used {{day}}, not just the lines after the third ng-init. There are only a few appropriate uses of ng-init (such as aliasing special properties of ng-repeat) and this is not one of those cases.

An example of how the code could work without ng-init:

  <tr ng-repeat="x in [].constructor(6) track by $index">
    <td>
      <p>{{ monthOfData[7 * $index] }}</p>
    </td>
    <td>
      <p>{{ monthOfData[7 * $index + 1] }}</p>
    </td>
  </tr>

Or alternatively, since your td blocs are very similar, we could add a second loop like so:

  <tr ng-repeat="x in [].constructor(6) track by $index" ng-init="loopNumber = $index">
    <td ng-repeat="x in [].constructor(2) track by $index" ng-init="var = $index">
      <p>{{ monthOfData[7 * loopNumber + var] }}</p>
    </td>
  </tr>

Note how in this second example ng-init is used to alias the two instances of $index referring to the two different loops. This was not needed in the first example and we can use $index directly when evaluating the expressions.

Leave a Reply

Your email address will not be published. Required fields are marked *