197

I was wondering if there is a way in angular to conditionally display content other than using ng-show etc. For example in backbone.js I could do something with inline content in a template like:

<% if (myVar === "two") { %> show this<% } %>

but in angular, I seem to be limited to showing and hiding things wrapped in html tags

<p ng-hide="true">I'm hidden</p>
<p ng-show="true">I'm shown</p>

What is the recommended way in angular to conditionally show and hide inline content in angular just using {{}} rather than wrapping the content in html tags?

Damjan Pavlica
  • 21,431
  • 6
  • 55
  • 65
user1469779
  • 2,451
  • 4
  • 15
  • 21

11 Answers11

743

Angular 1.1.5 added support for ternary operators:

{{myVar === "two" ? "it's true" : "it's false"}}
2Toad
  • 13,711
  • 7
  • 38
  • 38
  • 14
    This answer with the most upvotes should appear at the top of the answers... it's by far the most correct – Code Whisperer Oct 07 '14 at 15:09
  • 3
    user1469779 consider accepting this answer as this is the recommended way of achieving what you want for quite some time – Filip Kis Nov 18 '14 at 14:46
  • 13
    @2Toad, my answer was old. this is the correct answer now, I don't know if the user will be back to "accept" it now, but I've annotated my answer as such. Such is the changing face of software development. – Ben Lesh Dec 03 '14 at 19:04
  • 2
    Thanks. How can I have it display the value of `myVar` only if it is false? (i.e. how can I nest variables in the expression?) I tried with `{{myVar === "two" ? "it's true" : {{myVar}}}}` but it doesn't work. – Josh Dec 11 '14 at 05:13
  • 6
    @Josh the `myVar` property doesn't need to be wrapped in additional curly braces, it's already inside an expression. Try `{{myVar === "two" ? "it's true" : myVar}}` – 2Toad Dec 12 '14 at 00:50
  • just used this in the wild in a directive to show or hide a show image link with the ternary with Angular 1.4.3 thank you much good sirs and ladies! `` – asherrard Aug 25 '15 at 14:37
  • Worked for me , i did `{{vm.StateName === "AA" ? "ALL" : vm.StateName}}` – Tom Stickel May 11 '17 at 21:09
  • my example : – zokaee hamid Feb 03 '19 at 19:31
140

EDIT: 2Toad's answer below is what you're looking for! Upvote that thing

If you're using Angular <= 1.1.4 then this answer will do:

One more answer for this. I'm posting a separate answer, because it's more of an "exact" attempt at a solution than a list of possible solutions:

Here's a filter that will do an "immediate if" (aka iif):

app.filter('iif', function () {
   return function(input, trueValue, falseValue) {
        return input ? trueValue : falseValue;
   };
});

and can be used like this:

{{foo == "bar" | iif : "it's true" : "no, it's not"}}
Community
  • 1
  • 1
Ben Lesh
  • 105,049
  • 47
  • 242
  • 231
  • Thank you blesh, this is what I was going for. However I notice that if I try to put an html tag in one of the values it breaks: {{thing.second == "two" | iif : "
      " : "
        "}} I realize that there may be better ways to do this in angular, but is there a way to escape "" so that tags can be output as part of the string?
    – user1469779 Jan 09 '13 at 21:16
  • 1
    ngBind doesn't allow HTML output, you'd want to use [ng-bind-html-unsafe](http://docs.angularjs.org/api/ng.directive:ngBindHtmlUnsafe) – Ben Lesh Jan 09 '13 at 21:41
  • The example of ng-binf-html-unsafe in the angular documentation uses it within a tag, for example . it may not be possible to do what I am trying to do inline. – user1469779 Jan 10 '13 at 15:18
  • I've honestly not tried that. To me something feels wrong about writing out HTML in that manner. But I don't know your specific use case. – Ben Lesh Jan 10 '13 at 15:24
  • What's the reason for `iif` and not `if`? – iConnor Aug 15 '13 at 19:48
  • 1
    IIF is the abbreviation for "Inline If". It's common in different programming languages... just not as common as ?: inline ifs. ;) – Ben Lesh Aug 15 '13 at 20:15
  • 18
    @BenLesh major props for editing your answer now that there's other options, good work. – Nick Coad Dec 14 '14 at 22:59
  • can i use it with an evaluation of a function call ? {{foo == myObj.IsSomething | iif : "::GetTrueText()" : "::GetFalseText()"}} ? – eran otzap Mar 26 '17 at 08:44
61

Thousands of ways to skin this cat. I realize you're asking about between {{}} speifically, but for others that come here, I think it's worth showing some of the other options.

function on your $scope (IMO, this is your best bet in most scenarios):

  app.controller('MyCtrl', function($scope) {
      $scope.foo = 1;

      $scope.showSomething = function(input) {
           return input == 1 ? 'Foo' : 'Bar';
      };
   });

 <span>{{showSomething(foo)}}</span>

ng-show and ng-hide of course:

 <span ng-show="foo == 1">Foo</span><span ng-hide="foo == 1">Bar</span>

ngSwitch

 <div ng-switch on="foo">
   <span ng-switch-when="1">Foo</span>
   <span ng-switch-when="2">Bar</span>
   <span ng-switch-default>What?</span>
 </div>

A custom filter as Bertrand suggested. (this is your best choice if you have to do the same thing over and over)

app.filter('myFilter', function() {
   return function(input) {
     return input == 1 ? 'Foo' : 'Bar';
   }
}

{{foo | myFilter}}

Or A custom directive:

app.directive('myDirective', function() {
   return {
     restrict: 'E',
     replace: true,
     link: function(scope, elem, attrs) {
       scope.$watch(attrs.value, function(v) {
          elem.text(v == 1 ? 'Foo': 'Bar');
       });
     }
   };
});


<my-directive value="foo"></my-directive>

Personally, in most cases I'd go with a function on my scope, it keeps the markup pretty clean, and it's quick and easy to implement. Unless, that is, you're going to be doing the same exact thing over and over again, in which case I'd go with Bertrand's suggestion and create a filter or possibly a directive, depending on the circumstances.

As always, the most important thing is that your solution is easy to maintain, and is hopefully testable. And that is going to depend completely on your specific situation.

Ben Lesh
  • 105,049
  • 47
  • 242
  • 231
18

I am using the following to conditionally set the class attr when ng-class can't be used (for example when styling SVG):

ng-attr-class="{{someBoolean && 'class-when-true' || 'class-when-false' }}"

The same approach should work for other attribute types.

(I think you need to be on latest unstable Angular to use ng-attr-, I'm currently on 1.1.4)

I have published an article on working with AngularJS+SVG that talks about this and related issues. http://www.codeproject.com/Articles/709340/Implementing-a-Flowchart-with-SVG-and-AngularJS

Ashley Davis
  • 9,255
  • 7
  • 58
  • 79
15

For checking a variable content and have a default text, you can use:

<span>{{myVar || 'Text'}}</span>
ezequielc
  • 235
  • 2
  • 7
3

If I understood you well I think you have two ways of doing it.

First you could try ngSwitch and the second possible way would be creating you own filter. Probably ngSwitch is the right aproach but if you want to hide or show inline content just using {{}} filter is the way to go.

Here is a fiddle with a simple filter as an example.

<div ng-app="exapleOfFilter">
  <div ng-controller="Ctrl">
    <input ng-model="greeting" type="greeting">
      <br><br>
      <h1>{{greeting|isHello}}</h1>
  </div>
</div>

angular.module('exapleOfFilter', []).
  filter('isHello', function() {
    return function(input) {
      // conditional you want to apply
      if (input === 'hello') {
        return input;
      }
      return '';
    }
  });

function Ctrl($scope) {
  $scope.greeting = 'hello';
}
Bertrand
  • 13,340
  • 5
  • 37
  • 48
3

Angular UI library has built-in directive ui-if for condition in template/Views upto angular ui 1.1.4

Example: Support in Angular UI upto ui 1.1.4

<div ui-if="array.length>0"></div>

ng-if available in all the angular version after 1.1.4

<div ng-if="array.length>0"></div>

if you have any data in array variable then only the div will appear

JQuery Guru
  • 6,845
  • 1
  • 29
  • 39
  • `ui-if` was removed at least from latest version angular-ui but since angular 1.1.5 you have `ng-if` (from [this comment](http://stackoverflow.com/a/17812746/123033)) – Dave Everitt Oct 28 '13 at 15:56
2

So with Angular 1.5.1 ( had existing app dependency on some other MEAN stack dependencies is why I'm not currently using 1.6.4 )

This works for me like the OP saying {{myVar === "two" ? "it's true" : "it's false"}}

{{vm.StateName === "AA" ? "ALL" : vm.StateName}}
Tom Stickel
  • 16,699
  • 6
  • 102
  • 108
2

if you want to display "None" when value is "0", you can use as:

<span> {{ $scope.amount === "0" ?  $scope.amount : "None" }} </span>

or true false in angular js

<span> {{ $scope.amount === "0" ?  "False" : "True" }} </span>
Rizo
  • 2,391
  • 1
  • 15
  • 18
1

Works even in exotic Situations:

<br ng-show="myCondition == true" />
Steffomio
  • 338
  • 3
  • 6
0

I'll throw mine in the mix:

https://gist.github.com/btm1/6802312

this evaluates the if statement once and adds no watch listener BUT you can add an additional attribute to the element that has the set-if called wait-for="somedata.prop" and it will wait for that data or property to be set before evaluating the if statement once. that additional attribute can be very handy if you're waiting for data from an XHR request.

angular.module('setIf',[]).directive('setIf',function () {
    return {
      transclude: 'element',
      priority: 1000,
      terminal: true,
      restrict: 'A',
      compile: function (element, attr, linker) {
        return function (scope, iterStartElement, attr) {
          if(attr.waitFor) {
            var wait = scope.$watch(attr.waitFor,function(nv,ov){
              if(nv) {
                build();
                wait();
              }
            });
          } else {
            build();
          }

          function build() {
            iterStartElement[0].doNotMove = true;
            var expression = attr.setIf;
            var value = scope.$eval(expression);
            if (value) {
              linker(scope, function (clone) {
                iterStartElement.after(clone);
                clone.removeAttr('set-if');
                clone.removeAttr('wait-for');
              });
            }
          }
        };
      }
    };
  });
btm1
  • 3,831
  • 2
  • 20
  • 26