web-dev-qa-db-ja.com

Angular.js ng-switch-動的データを使用しない場合

私はAngularを取得して、データに基づいてCSSスライダーを生成しようとしています。データが存在し、ボタン用に生成できることを知っていますが、コードは生成されませんng-switch-when何らかの理由で。コードを検査すると、これが2回表示されます(2つのアイテムしか持っていないので正しいことがわかります)。

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

私の実際のコード:

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

編集:これは私がエミュレートしようとしているものですが、動的データを使用しています。 http://plnkr.co/edit/WUCyCN68tDR1YzNnCWyS?p=preview

29
user1855009

docs

照合する属性値は式にできないことに注意してください。これらは、照合するリテラル文字列値として解釈されます。たとえば、ng-switch-when = "someVal"は、式$ scope.someValの値ではなく、文字列 "someVal"と一致します。

つまり、ng-switchはテンプレートの条件をハードコーディングするためのものです。

次のように使用します。

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

現在、これはユースケースに正確に適合しない可能性があるため、戦略を再考する必要がある可能性があります。

Ng-Ifはおそらく必要なものです—また、 "isolated" scopes に注意する必要があります。基本的に、ng-repeatなどの特定のディレクティブを使用すると、親から分離された新しいスコープが作成されます。したがって、リピーターの内部でthisAssignmentを変更すると、コントローラー全体ではなく、特定のリピートブロック内の変数が実際に変更されます。

これが、目的の デモ です。

選択したプロパティをthings配列(単なるオブジェクト)に割り当てていることに注意してください。


更新12/12/14:ng-switchの使用を明確にするための新しいコードブロックの追加。上記のコード例は、何をするnotかを考慮する必要があります。

私のコメントで述べたように。スイッチは、JavaScriptスイッチとまったく同じように考える必要があります。ハードコーディングされたスイッチングロジック用です。したがって、たとえば私の投稿例では、数種類の投稿しかありません。スイッチをオンにする値のタイプについて、時間の先頭を知る必要があります。

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

この同じ機能をng-ifで実装できます。アプリケーション内で何が理にかなっているのかを決めるのはあなたの仕事です。この場合、後者の方がはるかに簡潔ですが、より複雑であり、テンプレートがより複雑な場合は、より毛むくじゃらになります。基本的な違いは、ng-switchは宣言的、ng-ifは必須です。

<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

ジョンは間違いなく正しい。 Angularは動的ngSwitchWhen値をサポートしていません。しかし、それを望んでいました。ngSwitchWhenの代わりに独自のディレクティブを使用するのは実際には非常に簡単でした。動的な値をサポートしますが、各ステートメントに対して複数の値をサポートします(JSスイッチのフォールスルーと同様)。

ただし、コンパイル時に式を評価するのは一度だけなので、正しい値をすぐに返す必要があります。アプリケーションの別の場所で定義された定数を使用したいので、私の目的ではこれで問題ありませんでした。おそらく式を動的に再評価するように変更できますが、それにはngSwitchでさらにテストする必要があります。

私はangular 1.3.15を使用していますが、angular 1.4.7で簡単なテストを実行しました。

Plunker Demo

コード

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 });
            });
        }
    };
});

使用法

  $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