Search code examples
angularjsangularjs-ng-repeatng-init

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.


Solution

  • 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.