web-dev-qa-db-fra.com

Angular.js ng-switch-lorsque vous ne travaillez pas avec des données dynamiques?

J'essaie d'obtenir Angular pour générer un curseur CSS basé sur mes données. Je sais que les données sont là et je peux les générer pour les boutons, mais le code ne remplira pas le ng-switch-when pour une raison quelconque. Lorsque j'inspecte le code, je le vois deux fois (ce que je sais être correct car je n'ai que deux éléments):

<div ng-repeat="assignment in assignments" ng-animate="'animate'" class="ng-scope">
    <!-- ngSwitchWhen: {{assignment.id}} -->
</div>

Mon code actuel:

<div ng-init="thisAssignment='one'">
     <div class="btn-group assignments" style="display: block; text-align: center; margin-bottom: 10px">
         <span ng-repeat="assignment in assignments">
              <button ng-click="thisAssignment = '{{assignment.id}}'" class="btn btn-primary">{{assignment.num}}</button>
         </span>
     </div>

     <div class="well" style="height: 170px;">
         <div ng-switch="thisAssignment">
              <div class="assignments">
                   <div ng-repeat="assignment in assignments" ng-animate="'animate'">
                        <div ng-switch-when='{{assignment.id}}' class="my-switch-animation">
                        <h2>{{assignment.name}}</h2>
                        <p>{{assignment.text}}</p>
                   </div>
              </div>
         </div>  
    </div>  
</div>

EDIT: C'est ce que j'essaie d'imiter, bien qu'avec des données dynamiques. http://plnkr.co/edit/WUCyCN68tDR1YzNnCWyS?p=preview

29
user1855009

De la docs -

N'oubliez pas que les valeurs d'attribut à comparer ne peuvent pas être des expressions. Ils sont interprétés comme des valeurs de chaînes littérales à comparer. Par exemple, ng-switch-when = "someVal" correspondra à la chaîne "someVal" et non à la valeur de l'expression $ scope.someVal.

En d'autres termes, ng-switch est destiné aux conditions de codage en dur dans vos modèles.

Vous l'utiliseriez ainsi:

<div class="assignments">
  <div ng-repeat="assignment in assignments" ng-animate="'animate'">
    <div ng-switch="assignment.id">
      <div ng-switch-when='1' class="my-switch-animation">
      <h2>{{assignment.name}}</h2>
      <p>{{assignment.text}}</p>
    </div>
  </div>
</div>

Maintenant, cela pourrait ne pas correspondre exactement à votre cas d'utilisation, il est donc possible que vous deviez repenser votre stratégie.

Ng-If est probablement ce dont vous avez besoin - vous devez également être conscient de étendues "isolées" . Fondamentalement, lorsque vous utilisez certaines directives, comme ng-repeat, vous créez de nouvelles étendues qui sont isolées de leurs parents. Donc, si vous changez thisAssignment à l'intérieur d'un répéteur, vous changez en fait la variable à l'intérieur de ce bloc de répétition spécifique et non le contrôleur entier.

Voici une démo de ce que vous cherchez.

Remarquez que j'affecte la propriété sélectionnée au tableau things (c'est juste un objet).


Mise à jour 12/12/14: Ajout d'un nouveau bloc de code pour clarifier l'utilisation de ng-switch. L'exemple de code ci-dessus doit être considéré comme ce que ne doit pas faire.

Comme je l'ai mentionné dans mon commentaire. Le commutateur doit être pensé exactement comme un commutateur JavaScript. C'est pour la logique de commutation codée en dur. Ainsi, par exemple, dans mes exemples de messages, il n'y aura que quelques types de messages. Vous devriez connaître une tête de temps les types de valeurs que vous allez allumer.

<div ng-repeat="post in posts">
  <div ng-switch on="post.type">

    <!-- post.type === 'image' -->
    <div ng-switch-when="image" class="post post-image">
      <img ng-src="{{ post.image }} />
      <div ng-bind="post.content"></div>
    </div>

    <!-- post.type === 'video' -->
    <div ng-switch-when="video" class="post post-video">
      <video ng-src="{{ post.video }} />
      <div ng-bind="post.content"></div>
    </div>

    <!-- when above doesn't match -->
    <div ng-switch-default class="post">
      <div ng-bind="post.content"></div>
    </div>
  </div>
</div>

Vous pouvez implémenter cette même fonctionnalité avec ng-if, c'est à vous de décider ce qui a du sens dans votre candidature. Dans ce cas, ce dernier est beaucoup plus succinct, mais aussi plus compliqué, et vous pourriez le voir devenir beaucoup plus velu si le modèle était plus complexe. La distinction de base est ng-switch est déclaratif, ng-if est impératif.

<div ng-repeat="post in posts">
  <div class="post" ng-class="{
      'post-image': post.type === 'image', 
      'post-video': post.type === 'video'">
    <video ng-if="post.type === 'video'" ng-src="post.video" />
    <img ng-if="post.type === 'image'" ng-src="post.image" />
    <div ng-bind="post.content" />
  </div>
</div>
47
Jon Jaques

Jon a définitivement raison. Angular ne prend pas en charge les valeurs dynamiques de ngSwitchWhen. Mais je le voulais. J'ai trouvé en fait exceptionnellement simple d'utiliser ma propre directive à la place de ngSwitchWhen. Pas il ne prend en charge que les valeurs dynamiques, mais il prend en charge plusieurs valeurs pour chaque instruction (semblable aux relais JS).

Une mise en garde, il n'évalue l'expression qu'une seule fois au moment de la compilation, vous devez donc retourner immédiatement la valeur correcte. Pour mes besoins, c'était bien car je voulais utiliser des constantes définies ailleurs dans l'application. Il pourrait probablement être modifié pour réévaluer dynamiquement les expressions mais cela nécessiterait plus de tests avec ngSwitch.

J'utilise angular 1.3.15 mais j'ai effectué un test rapide avec angular 1.4.7 et cela a bien fonctionné là aussi.

Démo Plunker

Le code

module.directive('jjSwitchWhen', function() {
    // Exact same definition as ngSwitchWhen except for the link fn
    return {
        // Same as ngSwitchWhen
        priority: 1200,
        transclude: 'element',
        require: '^ngSwitch',
        link: function(scope, element, attrs, ctrl, $transclude) {
            var caseStms = scope.$eval(attrs.jjSwitchWhen);
            caseStms = angular.isArray(caseStms) ? caseStms : [caseStms];

            angular.forEach(caseStms, function(caseStm) {
                caseStm = '!' + caseStm;
                ctrl.cases[caseStm] = ctrl.cases[caseStm] || [];
                ctrl.cases[caseStm].Push({ transclude: $transclude, element: element });
            });
        }
    };
});

Usage

  $scope.types = {
      audio: '.mp3', 
      video: ['.mp4', '.gif'],
      image: ['.jpg', '.png', '.gif'] // Can have multiple matching cases (.gif)
  };
  <div ng-switch="mediaType">
    <div jj-switch-when="types.audio">Audio</div>

    <div jj-switch-when="types.video">Video</div>

    <div jj-switch-when="types.image">Image</div>

    <!-- Even works with ngSwitchWhen -->
    <div ng-switch-when=".docx">Document</div>

    <div ng-switch-default>Invalid Type</div>
  <div>
11
Joel Jeske