condicionales en línea en angular.js

192

Me preguntaba si hay una forma en angular para mostrar contenido condicional que no sea ng-show, etc. Por ejemplo, en backbone.js podría hacer algo con contenido en línea en una plantilla como:

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

pero en angular, parece que estoy limitado a mostrar y ocultar cosas envueltas en etiquetas html

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

¿Cuál es la forma recomendada en angular para mostrar y ocultar condicionalmente el contenido en línea en angular simplemente usando {{}} en lugar de envolver el contenido en etiquetas html?

usuario1469779
fuente
66
acepte mi respuesta y acepte 2Toad cuando tenga la oportunidad.
Ben Lesh

Respuestas:

139

EDITAR: ¡La respuesta de 2Toad a continuación es lo que estás buscando! Vota esa cosa

Si está utilizando Angular <= 1.1.4, esta respuesta servirá:

Una respuesta más para esto. Estoy publicando una respuesta por separado, porque es más un intento "exacto" de solución que una lista de posibles soluciones:

Aquí hay un filtro que hará un "if inmediato" (también conocido como iif):

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

y se puede usar así:

{{foo == "bar" | iif : "it's true" : "no, it's not"}}
Ben Lesh
fuente
Gracias carne, esto es lo que estaba buscando. Sin embargo, noto que si trato de poner una etiqueta html en uno de los valores se rompe: {{thing.second == "two" | iif: "<ul class = 'two-class'>": "<ul>"}} Me doy cuenta de que puede haber mejores formas de hacerlo en angular, pero ¿hay alguna forma de escapar de "<" y ">" para que las etiquetas puedan salir como parte de la cadena?
user1469779
1
ngBind no permite la salida HTML, querrás usar ng-bind-html-inseguro
Ben Lesh
El ejemplo de ng-binf-html-inseguro en la documentación angular lo usa dentro de una etiqueta, por ejemplo <ANY ng-bind-html-unsafe = "{expression}">. Puede que no sea posible hacer lo que estoy tratando de hacer en línea.
user1469779
1
IIF es la abreviatura de "Inline If". Es común en diferentes lenguajes de programación ... pero no tan común como?: Ifs en línea. ;)
Ben Lesh
18
@BenLesh principales accesorios para editar su respuesta ahora que hay otras opciones, buen trabajo.
Nick Coad
724

Angular 1.1.5 agregó soporte para operadores ternarios:

{{myVar === "two" ? "it's true" : "it's false"}}
2 sapo
fuente
14
Esta respuesta con la mayoría de los votos a favor debería aparecer en la parte superior de las respuestas ... es, con mucho, la más correcta
Code Whisperer
3
user1469779 considere aceptar esta respuesta, ya que esta es la forma recomendada de lograr lo que desea durante bastante tiempo
Filip Kis
13
@ 2 Sapo, mi respuesta era vieja. esta es la respuesta correcta ahora, no sé si el usuario volverá a "aceptarla" ahora, pero he anotado mi respuesta como tal. Tal es la cara cambiante del desarrollo de software.
Ben Lesh
2
Gracias. ¿Cómo puedo hacer que muestre el valor myVarsolo si es falso? (es decir, ¿cómo puedo anidar variables en la expresión?) Intenté {{myVar === "two" ? "it's true" : {{myVar}}}}pero no funciona.
Josh
66
@ Josh, la myVarpropiedad no necesita estar envuelta en llaves adicionales, ya está dentro de una expresión. Prueba{{myVar === "two" ? "it's true" : myVar}}
2Toad
60

Miles de formas de pelar a este gato. Me doy cuenta de que estás preguntando entre {{}} específicamente, pero para otros que vienen aquí, creo que vale la pena mostrar algunas de las otras opciones.

funciona en tu $ scope (IMO, esta es tu mejor apuesta en la mayoría de los escenarios):

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

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

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

ng-show y ng-hide, por supuesto:

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

Un filtro personalizado como Bertrand sugirió. (esta es su mejor opción si tiene que hacer lo mismo una y otra vez)

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

{{foo | myFilter}}

O una directiva personalizada:

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>

Personalmente, en la mayoría de los casos, iría con una función en mi alcance, mantiene el marcado bastante limpio, y es rápido y fácil de implementar. A menos que, va a hacer exactamente lo mismo una y otra vez, en cuyo caso iría con la sugerencia de Bertrand y crearía un filtro o posiblemente una directiva, dependiendo de las circunstancias.

Como siempre, lo más importante es que su solución es fácil de mantener y es de esperar que sea comprobable. Y eso va a depender completamente de su situación específica.

Ben Lesh
fuente
18

Estoy usando lo siguiente para configurar condicionalmente la clase attr cuando no se puede usar ng-class (por ejemplo, al diseñar SVG):

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

El mismo enfoque debería funcionar para otros tipos de atributos.

(Creo que necesitas estar en el último Angular inestable para usar ng-attr-, actualmente estoy en 1.1.4)

He publicado un artículo sobre cómo trabajar con AngularJS + SVG que habla sobre este y otros temas relacionados. http://www.codeproject.com/Articles/709340/Implementing-a-Flowchart-with-SVG-and-AngularJS

Ashley Davis
fuente
15

Para verificar un contenido variable y tener un texto predeterminado, puede usar:

<span>{{myVar || 'Text'}}</span>
ezequielc
fuente
1
¡gracias! Estaba intentando esto pero me faltan las comillas :-)
Simona Adriani
Por alguna razón, esta sintaxis no funciona utilizando enlaces únicos .. {{:: myVar || 'Texto'}} no funcionará. Debe estar sin el ::
aoakeson
3

Si te entendí bien, creo que tienes dos formas de hacerlo.

Primero, puede probar ngSwitch y la segunda forma posible sería crear su propio filtro . Probablemente ngSwitch es el enfoque correcto, pero si desea ocultar o mostrar contenido en línea, simplemente usar el filtro {{}} es el camino a seguir.

Aquí hay un violín con un filtro simple como ejemplo.

<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
fuente
3

La biblioteca de IU angular tiene una directiva integrada ui-if para la condición en la plantilla / Vistas hasta ui angular 1.1.4

Ejemplo: soporte en IU angular hasta ui 1.1.4

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

ng-si está disponible en todas las versiones angulares después de 1.1.4

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

si tiene datos en la variable de matriz, solo aparecerá el div

JQuery Guru
fuente
ui-iffue eliminado al menos de la última versión angular-ui pero desde angular 1.1.5 tienes ng-if(de este comentario )
Dave Everitt
2

Entonces, con Angular 1.5.1 (tenía una dependencia de aplicación existente en algunas otras dependencias de la pila MEAN, es por eso que actualmente no estoy usando 1.6.4)

Esto funciona para mí como dice el OP {{myVar === "two" ? "it's true" : "it's false"}}

{{vm.StateName === "AA" ? "ALL" : vm.StateName}}
Tom Stickel
fuente
2

si desea mostrar "Ninguno" cuando el valor es "0", puede usarlo como:

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

o verdadero falso en angular js

<span> {{ $scope.amount === "0" ?  "False" : "True" }} </span>
Rizo
fuente
1

Funciona incluso en situaciones exóticas:

<br ng-show="myCondition == true" />
Steffomio
fuente
0

Tiraré el mío en la mezcla:

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

esto evalúa la instrucción if una vez y no agrega watch listener PERO puede agregar un atributo adicional al elemento que tiene el set-if llamado wait-for = "somedata.prop" y esperará a que se establezcan esos datos o propiedades antes evaluando la declaración if una vez. ese atributo adicional puede ser muy útil si está esperando datos de una solicitud XHR.

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
fuente