Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular.js ng-switch-when not working with dynamic data?

I'm trying to get Angular to generate a CSS slider based on my data. I know that the data is there and am able to generate it for the buttons, but the code won't populate the ng-switch-when for some reason. When I inspect the code, I see this twice (which I know to be correct as I only have two items):

<div ng-repeat="assignment in assignments" ng-animate="'animate'" class="ng-scope">     <!-- ngSwitchWhen: {{assignment.id}} --> </div> 

My actual code:

<div ng-init="thisAssignment='one'">      <div class="btn-group assignments" style="display: block; text-align: center; margin-bottom: 10px">          <span ng-repeat="assignment in assignments">               <button ng-click="thisAssignment = '{{assignment.id}}'" class="btn btn-primary">{{assignment.num}}</button>          </span>      </div>       <div class="well" style="height: 170px;">          <div ng-switch="thisAssignment">               <div class="assignments">                    <div ng-repeat="assignment in assignments" ng-animate="'animate'">                         <div ng-switch-when='{{assignment.id}}' class="my-switch-animation">                         <h2>{{assignment.name}}</h2>                         <p>{{assignment.text}}</p>                    </div>               </div>          </div>       </div>   </div> 

EDIT: This is what I'm trying to emulate, though with dynamic data. http://plnkr.co/edit/WUCyCN68tDR1YzNnCWyS?p=preview

like image 672
user1855009 Avatar asked Feb 05 '14 00:02

user1855009


People also ask

What is the use of NG switch and Ng switch when directives?

Definition and UsageThe ng-switch directive lets you hide/show HTML elements depending on an expression. Child elements with the ng-switch-when directive will be displayed if it gets a match, otherwise the element, and its children will be removed.

What is ngSwitch?

In Angular 8, ngSwitch is a structural directive which is used to Add/Remove DOM Element. It is similar to switch statement of C#. The ngSwitch directive is applied to the container element with a switch expression.

Is ng show a directive?

AngularJS ng-show DirectiveThe ng-show directive shows the specified HTML element if the expression evaluates to true, otherwise the HTML element is hidden.

What type of directive is ngSwitch?

The ngSwitch is an Angular structural directive, which allows us to add or remove DOM elements. It works in conjunction with ngSwitchcase , & ngSwitchDefault directives. It is similar to the switch statement of JavaScript.


2 Answers

From the docs —

Be aware that the attribute values to match against cannot be expressions. They are interpreted as literal string values to match against. For example, ng-switch-when="someVal" will match against the string "someVal" not against the value of the expression $scope.someVal.

So in other words, ng-switch is for hardcoding conditions in your templates.

You would use it like so:

<div class="assignments">   <div ng-repeat="assignment in assignments" ng-animate="'animate'">     <div ng-switch="assignment.id">       <div ng-switch-when='1' class="my-switch-animation">       <h2>{{assignment.name}}</h2>       <p>{{assignment.text}}</p>     </div>   </div> </div> 

Now this might not fit your use case exactly, so it's possible you'll have to rethink your strategy.

Ng-If is probably what you need — also, you need to be aware of "isolated" scopes. Basically when you use certain directives, like ng-repeat, you create new scopes which are isolated from their parents. So if you change thisAssignmentinside a repeater, you're actually changing the variable inside that specific repeat block and not the whole controller.

Here's a demo of what you're going for.

Notice I assign the selected property to the things array (it's just an object).


Update 12/12/14: Adding a new block of code to clarify the use of ng-switch. The code example above should be considered what not to do.

As I mentioned in my comment. Switch should be thought about exactly like a JavaScript switch. It's for hardcoded switching logic. So for instance in my example posts, there are only going to be a few types of posts. You should know a head of time the types of values you are going to be switching on.

<div ng-repeat="post in posts">   <div ng-switch on="post.type">      <!-- post.type === 'image' -->     <div ng-switch-when="image" class="post post-image">       <img ng-src="{{ post.image }} />       <div ng-bind="post.content"></div>     </div>      <!-- post.type === 'video' -->     <div ng-switch-when="video" class="post post-video">       <video ng-src="{{ post.video }} />       <div ng-bind="post.content"></div>     </div>          <!-- when above doesn't match -->     <div ng-switch-default class="post">       <div ng-bind="post.content"></div>     </div>   </div> </div> 

You could implement this same functionality with ng-if, it's your job to decide what makes sense within your application. In this case the latter is much more succinct, but also more complicated, and you could see it getting much more hairy if the template were any more complex. Basic distinction is ng-switch is declarative, ng-if is imperative.

<div ng-repeat="post in posts">   <div class="post" ng-class="{       'post-image': post.type === 'image',        'post-video': post.type === 'video'">     <video ng-if="post.type === 'video'" ng-src="post.video" />     <img ng-if="post.type === 'image'" ng-src="post.image" />     <div ng-bind="post.content" />   </div> </div> 
like image 126
Jon Jaques Avatar answered Oct 21 '22 14:10

Jon Jaques


Jon is definitely right on. Angular does not support dynamic ngSwitchWhen values. But I wanted it to. I found it actually exceptionally simple to use my own directive in place of ngSwitchWhen. Not only does it support dynamic values but it supports multiple values for each statement (similar to JS switch fall-throughs).

One caveat, it only evaluates the expression once upon compile time, so you must return the correct value immediately. For my purposes this was fine as I was wanting to use constants defined elsewhere in the application. It could probably be modified to dynamically re-evaluate the expressions but that would require more testing with ngSwitch.

I am use angular 1.3.15 but I ran a quick test with angular 1.4.7 and it worked fine there as well.

Plunker Demo

The Code

module.directive('jjSwitchWhen', function() {     // Exact same definition as ngSwitchWhen except for the link fn     return {         // Same as ngSwitchWhen         priority: 1200,         transclude: 'element',         require: '^ngSwitch',         link: function(scope, element, attrs, ctrl, $transclude) {             var caseStms = scope.$eval(attrs.jjSwitchWhen);             caseStms = angular.isArray(caseStms) ? caseStms : [caseStms];              angular.forEach(caseStms, function(caseStm) {                 caseStm = '!' + caseStm;                 ctrl.cases[caseStm] = ctrl.cases[caseStm] || [];                 ctrl.cases[caseStm].push({ transclude: $transclude, element: element });             });         }     }; }); 

Usage

Controller
  $scope.types = {       audio: '.mp3',        video: ['.mp4', '.gif'],       image: ['.jpg', '.png', '.gif'] // Can have multiple matching cases (.gif)   }; 
Template
  <div ng-switch="mediaType">     <div jj-switch-when="types.audio">Audio</div>      <div jj-switch-when="types.video">Video</div>      <div jj-switch-when="types.image">Image</div>      <!-- Even works with ngSwitchWhen -->     <div ng-switch-when=".docx">Document</div>      <div ng-switch-default>Invalid Type</div>   <div> 
like image 22
Joel Jeske Avatar answered Oct 21 '22 12:10

Joel Jeske