conditions en ligne dans angular.js

192

Je me demandais s'il y avait un moyen angulaire d'afficher conditionnellement du contenu autre que l'utilisation de ng-show, etc. Par exemple, dans backbone.js, je pourrais faire quelque chose avec du contenu en ligne dans un modèle comme:

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

mais en angulaire, je semble être limité à montrer et cacher les choses enveloppées dans des balises html

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

Quelle est la méthode recommandée en angulaire pour afficher et masquer de manière conditionnelle le contenu en ligne en angulaire en utilisant simplement {{}} plutôt que d'envelopper le contenu dans des balises html?

user1469779
la source
6
veuillez refuser ma réponse et accepter les 2Toad lorsque vous en aurez l'occasion.
Ben Lesh

Réponses:

139

EDIT: la réponse de 2Toad ci - dessous est ce que vous cherchez! Votez cette chose

Si vous utilisez Angular <= 1.1.4, cette réponse fera l'affaire:

Encore une réponse à cela. Je poste une réponse distincte, car il s'agit plus d'une tentative "exacte" de solution que d'une liste de solutions possibles:

Voici un filtre qui fera un "si immédiat" (alias iif):

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

et peut être utilisé comme ceci:

{{foo == "bar" | iif : "it's true" : "no, it's not"}}
Ben Lesh
la source
Merci blesh, c'est ce que j'allais faire. Cependant, je remarque que si j'essaie de mettre une balise html dans l'une des valeurs, elle casse: {{thing.second == "two" | iif: "<ul class = 'two-class'>": "<ul>"}} Je me rends compte qu'il peut y avoir de meilleures façons de le faire en angulaire, mais existe-t-il un moyen d'échapper à "<" et ">" afin que les balises puissent être sorties dans le cadre de la chaîne?
user1469779
1
ngBind n'autorise pas la sortie HTML, vous voudriez utiliser ng-bind-html-unsafe
Ben Lesh
L'exemple de ng-binf-html-unsafe dans la documentation angulaire l'utilise dans une balise, par exemple <ANY ng-bind-html-unsafe = "{expression}">. il n'est peut-être pas possible de faire ce que j'essaie de faire en ligne.
user1469779
1
IIF est l'abréviation de "Inline If". Il est courant dans différents langages de programmation ... mais pas aussi commun que?: If en ligne. ;)
Ben Lesh
18
@BenLesh principaux accessoires pour modifier votre réponse maintenant qu'il existe d'autres options, bon travail.
Nick Coad
724

Angular 1.1.5 a ajouté la prise en charge des opérateurs ternaires:

{{myVar === "two" ? "it's true" : "it's false"}}
2Toad
la source
14
Cette réponse avec le plus de votes devrait apparaître en haut des réponses ... c'est de loin la plus correcte
Code Whisperer
3
user1469779 envisagez d'accepter cette réponse car c'est la façon recommandée d'atteindre ce que vous voulez pendant un certain temps
Filip Kis
13
@ 2Toad, ma réponse était ancienne. c'est la bonne réponse maintenant, je ne sais pas si l'utilisateur sera de retour pour "l'accepter" maintenant, mais j'ai annoté ma réponse comme telle. Tel est le visage changeant du développement logiciel.
Ben Lesh
2
Merci. Comment puis-je lui faire afficher la valeur de myVarseulement si elle est fausse? (c'est-à-dire comment puis-je imbriquer des variables dans l'expression?) J'ai essayé avec {{myVar === "two" ? "it's true" : {{myVar}}}}mais cela ne fonctionne pas.
Josh
6
@Josh, la myVarpropriété n'a pas besoin d'être entourée d'accolades supplémentaires, elle est déjà à l'intérieur d'une expression. Essayez{{myVar === "two" ? "it's true" : myVar}}
2Toad
60

Des milliers de façons d'écorcher ce chat. Je me rends compte que vous posez des questions spécifiques entre {{}}, mais pour ceux qui viennent ici, je pense que cela vaut la peine de montrer certaines des autres options.

fonction sur votre portée $ (IMO, c'est votre meilleur pari dans la plupart des scénarios):

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

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

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

ng-show et ng-hide bien sûr:

 <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 filtre personnalisé comme l'a suggéré Bertrand. (c'est votre meilleur choix si vous devez faire la même chose encore et encore)

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

{{foo | myFilter}}

Ou une directive personnalisée:

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>

Personnellement, dans la plupart des cas, j'irais avec une fonction sur ma portée, cela garde le balisage assez propre et il est rapide et facile à implémenter. À moins que vous ne fassiez la même chose encore et encore, auquel cas j'irais avec la suggestion de Bertrand et créerais un filtre ou éventuellement une directive, selon les circonstances.

Comme toujours, la chose la plus importante est que votre solution est facile à entretenir et peut être testée, espérons-le. Et cela va dépendre complètement de votre situation spécifique.

Ben Lesh
la source
18

J'utilise ce qui suit pour définir conditionnellement la classe attr lorsque la classe ng ne peut pas être utilisée (par exemple lors du style SVG):

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

La même approche devrait fonctionner pour d'autres types d'attributs.

(Je pense que vous devez être sur le dernier Angular instable pour utiliser ng-attr-, je suis actuellement sur 1.1.4)

J'ai publié un article sur le travail avec AngularJS + SVG qui parle de cela et des problèmes connexes. http://www.codeproject.com/Articles/709340/Implementing-a-Flowchart-with-SVG-and-AngularJS

Ashley Davis
la source
15

Pour vérifier un contenu variable et avoir un texte par défaut, vous pouvez utiliser:

<span>{{myVar || 'Text'}}</span>
ezequielc
la source
1
Merci! J'essayais cela mais je manque les guillemets autour de la chaîne :-)
Simona Adriani
Pour une raison quelconque, cette syntaxe ne fonctionne pas en utilisant des liaisons uniques. {{:: myVar || 'Text'}} ne fonctionnera pas. Doit être sans ::
aoakeson
3

Si je vous ai bien compris, je pense que vous avez deux façons de procéder.

Vous pouvez d'abord essayer ngSwitch et la deuxième façon possible serait de créer votre propre filtre . Probablement, ngSwitch est la bonne approche, mais si vous voulez masquer ou afficher du contenu en ligne en utilisant simplement le filtre {{}}, c'est la voie à suivre.

Voici un violon avec un simple filtre comme exemple.

<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
la source
3

La bibliothèque de l'interface utilisateur angulaire a une directive intégrée ui-if pour la condition dans le modèle / Vues jusqu'à l'interface utilisateur angulaire 1.1.4

Exemple: prise en charge de l'interface utilisateur angulaire jusqu'à l'interface utilisateur 1.1.4

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

ng-si disponible dans toute la version angulaire après 1.1.4

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

si vous avez des données dans une variable de tableau, seul le div apparaîtra

JQuery Guru
la source
ui-ifa été supprimé au moins de la dernière version angular-ui mais depuis angular 1.1.5 vous avez ng-if(de ce commentaire )
Dave Everitt
2

Donc avec Angular 1.5.1 (avait une dépendance d'application existante sur d'autres dépendances de la pile MEAN, c'est pourquoi je n'utilise pas actuellement 1.6.4)

Cela fonctionne pour moi comme le dit l'OP {{myVar === "two" ? "it's true" : "it's false"}}

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

si vous voulez afficher "Aucun" lorsque la valeur est "0", vous pouvez utiliser comme:

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

ou vrai faux en js angulaire

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

Fonctionne même dans des situations exotiques:

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

Je vais jeter le mien dans le mix:

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

ceci évalue l'instruction if une fois et n'ajoute aucun écouteur de surveillance MAIS vous pouvez ajouter un attribut supplémentaire à l'élément qui a le set-if appelé wait-for = "somedata.prop" et il attendra que ces données ou propriétés soient définies avant évaluer l'instruction if une fois. cet attribut supplémentaire peut être très pratique si vous attendez des données d'une demande 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
la source