Подтвердить что ты не робот

Angular.js ng-switch - когда не работает с динамическими данными?

Я пытаюсь получить Angular для создания слайдера CSS на основе моих данных. Я знаю, что данные есть, и я могу сгенерировать его для кнопок, но код не будет заполнять ng-switch - когда по какой-то причине. Когда я проверяю код, я вижу это дважды (что, как я знаю, является правильным, поскольку у меня есть только два элемента):

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

EDIT: Это то, что я пытаюсь подражать, хотя и с динамическими данными. http://plnkr.co/edit/WUCyCN68tDR1YzNnCWyS?p=preview

4b9b3361

Ответ 1

Из docs -

Имейте в виду, что значения атрибутов, которые должны соответствовать, не могут быть выражениями. Они есть интерпретируются как литеральные строковые значения для соответствия. Например, ng-switch-when = "someVal" будет соответствовать строке "someVal" не против значения выражения $Scope.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, вероятно, то, что вам нужно - также вам нужно знать "изолированные" области. В основном, когда вы используете определенные директивы, например ng-repeat, вы создаете новые области, которые изолированы от своих родителей. Поэтому, если вы меняете thisAssignment внутри ретранслятора, вы фактически меняете переменную внутри этого конкретного блока повтора, а не весь контроллер.

Здесь демо того, что вы собираетесь делать.

Примечание. Я назначаю выбранное свойство массиву things (это просто объект).


Обновление 12/12/14: добавление нового блока кода для разъяснения использования ng-switch. Приведенный выше пример кода следует рассматривать как не.

Как я уже упоминал в своем комментарии. Переключатель следует рассматривать точно как переключатель 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>

Ответ 2

Джон определенно прав. Angular не поддерживает динамические значения ngSwitchWhen. Но я этого хотел. Я нашел, что на самом деле исключительно просто использовать мою собственную директиву вместо ngSwitchWhen. Он поддерживает не только динамические значения, но и поддерживает несколько значений для каждого оператора (аналогично провалу переключения JS).

Одно предупреждение, оно только оценивает выражение один раз во время компиляции, поэтому вы должны немедленно вернуть правильное значение. Для моих целей это было прекрасно, поскольку я хотел использовать константы, определенные в другом месте приложения. Вероятно, его можно было бы модифицировать для динамической переоценки выражений, но это потребовало бы большего тестирования с помощью ngSwitch.

Я использую Angular 1.3.15, но я провел быстрый тест с Angular 1.4.7, и он отлично работал там.

Демо-версия плунжера

Код

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>