condicionais inline em angular.js

192

Eu queria saber se existe uma maneira angular de exibir condicionalmente conteúdo que não seja o ng-show etc. Por exemplo, no backbone.js, eu poderia fazer algo com conteúdo embutido em um modelo como:

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

mas em angular, pareço estar limitado a mostrar e ocultar coisas envoltas em tags html

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

Qual é a maneira recomendada em angular de mostrar e ocultar condicionalmente o conteúdo embutido em angular usando {{}} em vez de agrupar o conteúdo em tags html?

user1469779
fonte
6
por favor, aceite minha resposta e aceite 2Toad's quando tiver uma chance.
Ben Lesh

Respostas:

139

EDIT: A resposta de 2Toad abaixo é o que você está procurando! Voto positivo nessa coisa

Se você estiver usando Angular <= 1.1.4, então esta resposta fará:

Mais uma resposta para isso. Estou postando uma resposta separada, porque é mais uma tentativa "exata" de uma solução do que uma lista de possíveis soluções:

Aqui está um filtro que fará um "imediato se" (aka iif):

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

e pode ser usado assim:

{{foo == "bar" | iif : "it's true" : "no, it's not"}}
Ben Lesh
fonte
Obrigado blesh, era para isso que eu estava indo. No entanto, percebo que, se eu tentar colocar uma tag html em um dos valores, ela será quebrada: {{thing.second == "two" | iif: "<ul class = 'two-class'>": "<ul>"}} Eu percebo que pode haver maneiras melhores de fazer isso em angular, mas existe uma maneira de escapar de "<" e ">" para que as tags possam ser exibidas como parte da string?
user1469779
1
não ngBind não permitir a saída HTML, você iria querer usar NG-bind-html-inseguro
Ben Lesh
O exemplo de ng-binf-html-unsafe na documentação angular usa-o em uma tag, por exemplo <QUALQUER ng-bind-html-unsafe = "{expression}">. talvez não seja possível fazer o que estou tentando fazer em linha.
precisa saber é o seguinte
1
IIF é a abreviação de "Inline If". É comum em diferentes linguagens de programação ... apenas não é tão comum quanto?: Ifs inline. ;)
Ben Lesh 15/08/13
18
Os principais recursos do @BenLesh para editar sua resposta agora que existem outras opções, bom trabalho.
precisa
724

O Angular 1.1.5 adicionou suporte para operadores ternários:

{{myVar === "two" ? "it's true" : "it's false"}}
2Carga
fonte
14
Essa resposta com o maior upvotes deve aparecer no topo das respostas ... é, de longe, o mais correto
Código Whisperer
3
user1469779 considerar aceitar esta resposta como esta é a maneira recomendada de alcançar o que você quer por algum tempo
Filip Kis
13
@ 2Toad, minha resposta foi antiga. esta é a resposta correta agora, não sei se o usuário voltará a "aceitá-la" agora, mas anotei minha resposta como tal. Essa é a nova face do desenvolvimento de software.
Ben Lesh
2
Obrigado. Como posso exibir o valor myVarsomente se for falso? (ou seja, como posso aninhar variáveis ​​na expressão?) Tentei com {{myVar === "two" ? "it's true" : {{myVar}}}}mas não funciona.
21713 Josh
6
@ Josh a myVarpropriedade não precisa ser envolvida em chaves adicionais, ela já está dentro de uma expressão. Tente{{myVar === "two" ? "it's true" : myVar}}
2Toad
60

Milhares de maneiras de esfolar esse gato. Sei que você está perguntando entre {{}} especificamente, mas para outros que vêm aqui, acho que vale a pena mostrar algumas das outras opções.

função no seu escopo $ (IMO, esta é sua melhor aposta na maioria dos cenários):

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

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

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

ng-show e ng-hide, é claro:

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

Um filtro personalizado, como sugeriu Bertrand. (esta é sua melhor escolha se você tiver que fazer a mesma coisa repetidamente)

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

{{foo | myFilter}}

Ou uma diretiva 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>

Pessoalmente, na maioria dos casos, eu usaria uma função no meu escopo, ela mantém a marcação bastante limpa e é rápida e fácil de implementar. A menos que você faça a mesma coisa repetidas vezes, nesse caso, eu iria com a sugestão de Bertrand e criaria um filtro ou possivelmente uma diretiva, dependendo das circunstâncias.

Como sempre, o mais importante é que sua solução seja fácil de manter e esperamos que seja testável. E isso vai depender completamente da sua situação específica.

Ben Lesh
fonte
18

Estou usando o seguinte para definir condicionalmente a classe attr quando a classe ng não puder ser usada (por exemplo, ao estilizar SVG):

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

A mesma abordagem deve funcionar para outros tipos de atributos.

(Eu acho que você precisa estar no mais recente angular instável para usar ng-attr-, atualmente estou no 1.1.4)

Publiquei um artigo sobre como trabalhar com o AngularJS + SVG que fala sobre isso e questões relacionadas. http://www.codeproject.com/Articles/709340/Implementing-a-Flowchart-with-SVG-and-AngularJS

Ashley Davis
fonte
15

Para verificar um conteúdo variável e ter um texto padrão, você pode usar:

<span>{{myVar || 'Text'}}</span>
ezequielc
fonte
1
obrigado! Eu estava tentando isso, mas eu perde as aspas em torno da cadeia :-)
Simona Adriani
Por qualquer motivo, essa sintaxe não funciona usando ligações únicas. {{:: myVar || 'Texto'}} não funcionará. Deve ficar sem o ::
aoakeson
3

Se eu te entendi bem, acho que você tem duas maneiras de fazê-lo.

Primeiro você pode tentar o ngSwitch e a segunda maneira possível seria criar seu próprio filtro . Provavelmente o ngSwitch é a abordagem certa, mas se você deseja ocultar ou mostrar conteúdo embutido, basta usar o filtro {{}}.

Aqui está um violino com um filtro simples como exemplo.

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

A biblioteca de interface do usuário angular possui a diretiva interna ui-if para a condição no modelo / Visualizações até a interface angular 1.1.4

Exemplo: Suporte na interface do usuário angular até a interface do usuário 1.1.4

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

ng-se disponível em toda a versão angular após 1.1.4

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

se você tiver algum dado na variável array, somente a div aparecerá

JQuery Guru
fonte
ui-iffoi removido, pelo menos a partir última versão angular-ui mas desde angular 1.1.5 você tem ng-if(de este comentário )
Dave Everitt
2

Portanto, com o Angular 1.5.1 (tinha dependência de aplicativo existente em algumas outras dependências da pilha MEAN, é por isso que não estou usando o 1.6.4)

Isso funciona para mim como o OP dizendo {{myVar === "two" ? "it's true" : "it's false"}}

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

se você quiser exibir "Nenhum" quando o valor for "0", poderá usar como:

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

ou verdadeiro falso em js angulares

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

Funciona mesmo em situações exóticas:

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

Vou jogar o meu na mistura:

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

isso avalia a instrução if uma vez e não adiciona nenhum ouvinte de observação, mas você pode adicionar um atributo adicional ao elemento que possui o conjunto se chamado wait-for = "somedata.prop" e aguardará a definição desses dados ou propriedades antes avaliando a instrução if uma vez. esse atributo adicional pode ser muito útil se você estiver aguardando dados de uma solicitação 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
fonte