ng-switch and ng-repeat on the same element interfearing

Kevin picture Kevin · Mar 15, 2013 · Viewed 11.9k times · Source

I encountered behaviour in Angular I did not expect and the purpose of this post is to find out whether this is a bug or intended and possibly an explanation why it is intended.

First see this Plunkr: http://plnkr.co/edit/CB7k9r?p=preview . In the example I created an array called array with three object entries. Further I created a ng-switch based on the content of an input field (called toggle). When the value of toggle is 1 it should print all names of the objects in the array prefixed with "1" and otherwise prefixed with "other".

This does not work as intended an it shows an error:

Error: Argument '?' is required at assertArg 

However the same example rewritten (http://plnkr.co/edit/68Mfux?p=preview ) with an extra div around the list, the ng-switch moved to this div and the ng-switch-when moved from the li to the ul (separating the ng-repeat and the ng-switch-when) does work as intended.

Could someone explain why this is?

Answer

Tiago Roldão picture Tiago Roldão · Mar 15, 2013

It is "intentional", as it is a product of how angular handles ng-repeat. Essentially, multiple copies of the markup are cloned (the markup inside ng-repeat is used as a template) and are compiled individually for each element you are iterating. As such, angular is basically compiling 3 <li ng-switch-when='1' ....> and 3 <li ng-switch-default ....>, but doing so out of context - there is no ng-switch-on element to compare to.

You can see this happening by inspecting the resulting markup:

<ul ng-switch="" on="toggle">  
  <!-- ngRepeat: entry in array -->
  <!-- ngSwitchWhen: 1 -->
  <!-- ngSwitchWhen: 1 -->
  <!-- ngSwitchWhen: 1 -->
  <!-- ngRepeat: entry in array -->
  <!-- ngSwitchDefault:  -->
  <!-- ngSwitchDefault:  -->
  <!-- ngSwitchDefault:  -->        
</ul>

Both directives - ng-repeat and ng-switch - should be handled with care, as they (unlike, for instance, ng-show or ng-hide) heavily influence structure. The second (working) Plunker is the way to go - only work with directives AFTER (structure-wise, INSIDE) the ng-switch logic.