727

I want to do a condition in an AngularJS template. I fetch a video list from the Youtube API. Some of the videos are in 16:9 ratio and some are in 4:3 ratio.

I want to make a condition like this:

if video.yt$aspectRatio equals widescreen then 
    element's attr height="270px"
else
    element's attr height="360px"

I'm iterating the videos using ng-repeat. Have no idea what should I do for this condition:

  • Add a function in the scope?
  • Do it in template?
dpassage
  • 5,423
  • 3
  • 25
  • 53
vzhen
  • 11,137
  • 13
  • 56
  • 87

10 Answers10

1325

Angularjs (versions below 1.1.5) does not provide the if/else functionality . Following are a few options to consider for what you want to achieve:

(Jump to the update below (#5) if you are using version 1.1.5 or greater)

1. Ternary operator:

As suggested by @Kirk in the comments, the cleanest way of doing this would be to use a ternary operator as follows:

<span>{{isLarge ? 'video.large' : 'video.small'}}</span>

2. ng-switch directive:

can be used something like the following.

<div ng-switch on="video">
    <div ng-switch-when="video.large">
        <!-- code to render a large video block-->
    </div>
    <div ng-switch-default>
        <!-- code to render the regular video block -->
    </div>
</div>

3. ng-hide / ng-show directives

Alternatively, you might also use ng-show/ng-hide but using this will actually render both a large video and a small video element and then hide the one that meets the ng-hide condition and shows the one that meets ng-show condition. So on each page you'll actually be rendering two different elements.

4. Another option to consider is ng-class directive.

This can be used as follows.

<div ng-class="{large-video: video.large}">
    <!-- video block goes here -->
</div>

The above basically will add a large-video css class to the div element if video.large is truthy.

UPDATE: Angular 1.1.5 introduced the ngIf directive

5. ng-if directive:

In the versions above 1.1.5 you can use the ng-if directive. This would remove the element if the expression provided returns false and re-inserts the element in the DOM if the expression returns true. Can be used as follows.

<div ng-if="video == video.large">
    <!-- code to render a large video block-->
</div>
<div ng-if="video != video.large">
    <!-- code to render the regular video block -->
</div>
Mbengue Assane
  • 2,855
  • 1
  • 17
  • 14
Amyth
  • 32,527
  • 26
  • 93
  • 135
  • 10
    It should be `ng-switch on="video"` instead `ng-switch-on="video"` – czerasz Jul 07 '13 at 20:32
  • 3rd option should be `ng-class="{large-video:video.large}"` as per [docs](http://docs.angularjs.org/api/ng.directive:ngClass) – Alo Sarv Oct 11 '13 at 16:42
  • 4
    How do that? if(){} else if(){} else if(){} else {} But include in dom only one element – falko Dec 03 '13 at 14:43
  • 211
    Also ternary `{{isAdded ? 'Added' : 'Add to cart'}}` – Kirk Strobeck Jan 26 '14 at 11:22
  • 18
    Keep in mind that `ng-if` will NOT add the enclosed elements to the DOM until its condition evaluates to `true`, unlike `ng-hide` and `ng-show`. – Wilhelm Murdoch Jun 17 '14 at 01:19
  • To the comment of Kirk Strobeck, if you have an entity for each record, in my case RuleEntity has method isActive. in view {{rule.isActive() ? 'icon-pause' : 'icon-play'}} – Valentin Rusk Jun 08 '15 at 14:10
  • 1
    Why not simply `ng-switch="video"`? Some problem? or it was not available earlier? For me it it is working quite fine – Sami Jul 15 '15 at 10:58
  • 1
    @KirkStrobeck I think the ternary should be the **first** option in the answer. The power of ternary made much sense to me now via this example. The other options are cumbersome. Wow! – KhoPhi Apr 27 '16 at 19:08
  • Keep in mind that `ng-if` introduces an **isolated scope**, so that `$parent` becomes `$parent.$parent` in the body of `ng-if`. – David Salamon Jul 12 '16 at 12:31
  • Some html minifiers will have trouble with the ternary operator, for example: gulp-minify-html:1.0.4 – Pytry Sep 16 '16 at 19:08
  • I'm pretty sure all of the extra elements do get added to the page, until angular has a chance to clean them up. This could mean you start loading the large video unexpectedly. Try putting this into a block which you don't expect to be rendered: – Jeremy Lawson Jan 22 '17 at 20:30
  • Does anyone know about the efficiency of these methods? Is ng-switch easier for the browser to render than 2 ng-ifs? – Nathan Hazzard Apr 26 '17 at 15:08
182

In the latest version of Angular (as of 1.1.5), they have included a conditional directive called ngIf. It is different from ngShow and ngHide in that the elements aren't hidden, but not included in the DOM at all. They are very useful for components which are costly to create but aren't used:

<div ng-if="video == video.large">
    <!-- code to render a large video block-->
</div>
<div ng-if="video != video.large">
    <!-- code to render the regular video block -->
</div>
Brian Genisio
  • 47,787
  • 16
  • 124
  • 167
  • 6
    Keep in mind that `ng-if` introduces an **isolated scope**, so that `$parent` becomes `$parent.$parent` in the body of `ng-if`. – David Salamon Jul 12 '16 at 12:31
145

Ternary is the most clear way of doing this.

<div>{{ConditionVar ? 'varIsTrue' : 'varIsFalse'}}</div>
Oliver Dixon
  • 7,012
  • 5
  • 61
  • 95
52

Angular itself doesn't provide if/else functionality, but you can get it by including this module:

https://github.com/zachsnow/ng-elif

In its own words, it's just "a simple collection of control flow directives: ng-if, ng-else-if, and ng-else." It's easy and intuitive to use.

Example:

<div ng-if="someCondition">
    ...
</div>
<div ng-else-if="someOtherCondition">
    ...
</div>
<div ng-else>
    ...
</div>
fracz
  • 20,536
  • 18
  • 103
  • 149
lpappone
  • 2,755
  • 2
  • 15
  • 15
  • 1
    i dont want to repeat the code in div again and again. –  Jan 19 '17 at 13:15
  • 1
    You don't have to repeat anything -- you could as easily do `ng-if="someCondition && someOtherCondition"`. Perhaps I misunderstand? (I wrote that module -- it should work just like `if` and `else` in JS). – Zach Snow May 13 '17 at 03:01
  • 1
    This is an absolute lifesaver. This should be part of Angular core, it's indispensable in template coding. Way cleaner than having ternary operators all over the place, and overcomes the limitations of ng-switch not being able to evaluate expressions. – Nico Westerdale Aug 01 '17 at 22:12
  • Thanks @NicoWesterdale! Also, I added a richer version of ng-switch you might find useful: https://github.com/zachsnow/ng-cases – Zach Snow Oct 29 '17 at 00:01
30

You could use your video.yt$aspectRatio property directly by passing it through a filter, and binding the result to the height attribute in your template.

Your filter would look something like:

app.filter('videoHeight', function () {
  return function (input) {
    if (input === 'widescreen') {
      return '270px';
    } else {
      return '360px';
    }
  };
});

And the template would be:

<video height={{video.yt$aspectRatio | videoHeight}}></video>
Noah Freitas
  • 17,240
  • 10
  • 50
  • 67
  • How about your code when `video.yt$aspectRatio` is empty or undefined? Is it possible to apply a default value? – Fractaliste Mar 31 '14 at 14:50
13

In this case you want to "calculate" a pixel value depending of an object property.

I would define a function in the controller that calculates the pixel values.

In the controller:


$scope.GetHeight = function(aspect) {
   if(bla bla bla) return 270;
   return 360;
}

Then in your template you just write:


element height="{{ GetHeight(aspect) }}px "

Spock
  • 2,482
  • 29
  • 27
11

I agree that a ternary is extremely clean. Seems that it is very situational though as somethings I need to display div or p or table , so with a table I don't prefer a ternary for obvious reasons. Making a call to a function is typically ideal or in my case I did this:

<div ng-controller="TopNavCtrl">
        <div ng-if="info.host ==='servername'">
            <table class="table">
                <tr ng-repeat="(group, status) in user.groups">
                    <th style="width: 250px">{{ group }}</th>
                    <td><input type="checkbox" ng-model="user.groups[group]" /></td>
                </tr>
            </table>
        </div>
       <div ng-if="info.host ==='otherservername'">
            <table class="table">
                <tr ng-repeat="(group, status) in user.groups">
                    <th style="width: 250px">{{ group }}</th>
                    <td><input type="checkbox" ng-model="user.groups[group]" /></td>
                </tr>
            </table>
        </div>
</div>
Tom Stickel
  • 19,633
  • 6
  • 111
  • 113
4
    <div ng-if="modeldate==''"><span ng-message="required" class="change">Date is required</span> </div>

you can use the ng-if directive as above.

JBhardwaj
  • 41
  • 1
3

A possibility for Angular: I had to include an if - statement in the html part, I had to check if all variables of an URL that I produce are defined. I did it the following way and it seems to be a flexible approach. I hope it will be helpful for somebody.

The html part in the template:

    <div  *ngFor="let p of poemsInGrid; let i = index" >
        <a [routerLink]="produceFassungsLink(p[0],p[3])" routerLinkActive="active">
    </div>

And the typescript part:

  produceFassungsLink(titel: string, iri: string) {
      if(titel !== undefined && iri !== undefined) {
         return titel.split('/')[0] + '---' + iri.split('raeber/')[1];
      } else {
         return 'Linkinformation has not arrived yet';
      }
  }

Thanks and best regards,

Jan

1

ng If else statement

ng-if="receiptData.cart == undefined ? close(): '' ;"
Aamir Anwar
  • 147
  • 1
  • 6