Условная логика в шаблоне AngularJS

У меня есть шаблон angular, который выглядит так:

<div ng-repeat="message in data.messages" ng-class="message.type">

    <div class="info">
        <div class="type"></div>
        <div class="from">From Avatar</div>
        <div class="createdBy">Created By Avatar</div>
        <div class="arrowTo">
            <div class="arrow"></div>
            <div class="to">To Avatar</div>
        </div>
        <div class="date">
            <div class="day">25</div>
            <div class="month">Dec</div>
        </div>
    </div>

    <div class="main">
        <div class="content">
            <div class="heading2">{{message.title}}</div>
            <div ng-bind-html="message.content"></div>
        </div>

    </div>

    <br />
    <hr />
    <br />

</div>

Я установил JSfiddle, чтобы показать связанные данные.

Что мне нужно сделать, так это то, что div из "from" , "to" и "arrowTo" показывают условно, в зависимости от содержимого данных.

Журнал - это...

  • Если в данных есть объект "from" , тогда отобразите "из" div и привяжите данные, но не покажите div "createdBy" .
  • Если объект "from" отсутствует, но есть объект "createdBy" , тогда отобразите div "createdBy" и привяжите данные.
  • Если в данных есть объект "to", тогда отобразите div "arrowTo" и привяжите его.

Или на простом английском языке, если есть адрес, покажите его, иначе покажите, кто создал запись, а если есть адрес, то также покажите это.

Я изучил использование ng-switch, но я думаю, что мне пришлось бы добавить дополнительную разметку, которая оставила бы пустой div, если бы не было данных. Плюс мне нужно было бы установить директивы switch, и я не уверен, что это сработает.

Любые идеи?

UPDATE:

Если бы я написал свою собственную директиву (если бы я знал, как!), то вот какой-то псевдо-код, чтобы показать, как я хочу его использовать...

<div ng-if="showFrom()">
    From Template Goes Here
</div>
<div ng-if="showCreatedBy()">
    CreatedBy Template Goes Here
</div>
<div ng-if="showTo()">
    To Template Goes Here
</div>

Каждый из них исчезнет, ​​если функция/выражение оценивается как false.

Ответ 1

Angular 1.1.5 введена директива ng-if. Это лучшее решение для этой конкретной проблемы. Если вы используете более старую версию Angular, рассмотрите директиву angular -ui ui-if.

Если вы пришли сюда, ища ответы на общий вопрос "условная логика в шаблонах", также подумайте:


Оригинальный ответ:

Вот не очень хорошая директива "ng-if":

myApp.directive('ngIf', function() {
    return {
        link: function(scope, element, attrs) {
            if(scope.$eval(attrs.ngIf)) {
                // remove '<div ng-if...></div>'
                element.replaceWith(element.children())
            } else {
                element.replaceWith(' ')
            }
        }
    }
});

который позволяет использовать этот синтаксис HTML:

<div ng-repeat="message in data.messages" ng-class="message.type">
   <hr>
   <div ng-if="showFrom(message)">
       <div>From: {{message.from.name}}</div>
   </div>    
   <div ng-if="showCreatedBy(message)">
      <div>Created by: {{message.createdBy.name}}</div>
   </div>    
   <div ng-if="showTo(message)">
      <div>To: {{message.to.name}}</div>
   </div>    
</div>

Fiddle.

replaceWith() используется для удаления ненужного содержимого из DOM.

Кроме того, как я уже упоминал в Google+, ng-style можно, вероятно, использовать для условной загрузки фоновых изображений, если вы хотите использовать ng -show вместо пользовательской директивы. (В интересах других читателей Джон заявил в Google+: "Оба метода используют ng-show, которых я пытаюсь избежать, потому что он использует display: none и оставляет дополнительную разметку в DOM. Это особая проблема в этом сценарии, потому что скрытый элемент будет иметь фоновое изображение, которое по-прежнему будет загружено в большинстве браузеров." ).
См. также Как условно применить стили CSS в AngularJS?

angular -ui ui-if директива следит за изменениями условия if/expression. Мой нет. Таким образом, хотя моя простая реализация корректно обновит представление, если модель изменится так, что она влияет только на вывод шаблона, она не будет корректно обновлять представление, если изменяется ответ условия/выражения.

Например, если значение a from.name изменяется в модели, представление будет обновляться. Но если вы delete $scope.data.messages[0].from, имя будет удалено из представления, но шаблон не будет удален из представления, потому что выражение if-condition/не просматривается.

Ответ 2

Вы можете использовать директиву ngSwitch:

  <div ng-switch on="selection" >
    <div ng-switch-when="settings">Settings Div</div>
    <span ng-switch-when="home">Home Span</span>
    <span ng-switch-default>default</span>
  </div>

Если вы не хотите, чтобы DOM загружался с пустыми div, вам нужно создать свою настраиваемую директиву с помощью $http для загрузки (под) шаблонов и компиляции $, чтобы вставить ее в DOM, когда определенное условие достигло.

Это просто (непроверенный) пример. Его можно и нужно оптимизировать:

HTML:

<conditional-template ng-model="element" template-url1="path/to/partial1" template-url2="path/to/partial2"></div>

Директива

app.directive('conditionalTemplate', function($http, $compile) {
   return {
      restrict: 'E',
      require: '^ngModel',
      link: function(sope, element, attrs, ctrl) {
        // get template with $http
        // check model via ctrl.$viewValue
        // compile with $compile
        // replace element with element.replaceWith()
      }
   };
});

Ответ 3

Вы можете использовать ng-show для каждого элемента div в цикле. Это то, что вы хотели: http://jsfiddle.net/pGwRu/2/?

<div class="from" ng-show="message.from">From: {{message.from.name}}</div>