AngularJS模板中的条件逻辑


71

我有一个看起来像这样的有角模板...

<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来显示绑定的数据。

我需要做的是根据数据内容有条件地显示“ from”,“ to”和“ arrowTo” div。

日志是这个...

  • 如果数据中存在“ from”对象,则显示“ from” div并绑定数据,但不显示“ createdBy” div。
  • 如果没有“来自”对象,但是有“ createdBy”对象,则显示“ createdBy” div并绑定数据。
  • 如果数据中有一个“ to”对象,则显示“ arrowTo” div并将其绑定。

或用简单的英语显示,如果有一个发自地址,则显示它,否则,显示由谁创建记录,如果有一个至地址,则也显示该地址。

我已经研究过使用ng-switch,但是我想我必须添加额外的标记,如果没有数据,它将留下一个空的div。另外,我需要嵌套switch指令,但不确定是否可行。

有任何想法吗?

更新:

如果我要编写自己的指令(如果我知道怎么做!),那么这里有一些伪代码来说明我将如何使用它……

<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,则每一个都将消失。


我或多或少有相同的问题,最终我使用了Angular UI及其UI-IF实现。它从DOM中删除了我想要的内容,因此问题得以解决。有关更多信息,请参见:angular-ui.github.com
alainvd

Answers:


89

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>

小提琴

replaceWith()用于从DOM中删除不需要的内容。

另外,正如我在Google+上提到的那样,如果您想使用ng-show而不是自定义指令,则ng-style可以用于有条件地加载背景图片。(为了其他读者的利益,Jon在Google+上说:“这两种方法都使用ng-show,这是我要避免的方法,因为它使用display:none并在DOM中留下了额外的标记。在这种情况下,这是一个特殊的问题,因为隐藏的元素将具有背景图片,该图片仍将在大多数浏览器中加载。”)。
另请参阅如何在AngularJS中有条件地应用CSS样式?

角度的UI的UI-如果指令手表更改如果条件/表达。我的不是。因此,虽然我的简单实现可以在模型更改时正确地更新视图,从而仅影响模板输出,但是如果条件/表达式答案发生更改,则它不会正确地更新视图。

例如,如果模型中from.name的值更改,则视图将更新。但是,如果delete $scope.data.messages[0].from使用from,则将从视图中删除from名称,但不会从视图中删除模板,因为不会监视if-condition / expression。


1
谢谢Mark,我可能会使用UI-IF,因为您指出的原因,这可能是最安全的方式。但是,我查看了ui-if的代码,它正在做很多我不了解的事情,而且我总是对使用我不了解的代码感到紧张。
jonhobbs 2012年

我刚刚注意到,虽然ui-if不会替代自身,但它仍然在模板周围留下了包装div。大概是由于某种原因而要做的,这与想要在表达式上保持手表有关吗?
jonhobbs 2012年

20

您可以使用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>

如果不希望用空的div加载DOM,则需要使用$ http创建自定义指令,以加载(sub)模板,并使用$ compile在达到特定条件时将其注入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()
      }
   };
});

已尽我所能使用ng-switch创建了一个新提琴-jsfiddle.net/jon64digital/pGwRu/5-但是,出于某些原因,我认为它不会起作用。(1)-when =“”似乎不适用于检查属性是否丢失。(2)即使我相信DOM仍然会被空的div和额外的包装div所困扰。
jonhobbs 2012年

我还不够先进,无法编写自己的指令,但是从本能上来说,使用ajax调用获取模板感觉不对。是否可以在HTML中包含模板(在指令内部)?我猜该表达式将是指令标记(可以调用函数)上的一个属性。如果表达式的值为true,则内部模板将被绑定并显示;如果表达式的值为false,则将从DOM中删除该元素。
jonhobbs 2012年

您也可以使用硬编码模板(字符串)。但是这样一来,它的可重用性就会降低。
asgoth

我刚刚指出了Angular UI IF指令的方向。看起来像我需要的东西,但是我不知道它是如何工作的,所以当我不了解它在做什么时,我总是谨慎地在项目中盲目添加一些东西。
jonhobbs 2012年

Asgoth,我不是在谈论在指令的JS代码中对模板进行硬编码。我的意思是将其放在指令的外部标记之间,例如<conditional-template expression =“ evaluateThis()”>模板在这里</ conditional-template>。
jonhobbs 2012年

6

您可以在循环中的每个div元素上使用ng-show。这就是您想要的:http : //jsfiddle.net/pGwRu/2/吗?

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

1
我相信ng-hide只会设置display:none,它不会从DOM中删除任何内容。
jonhobbs

同样,在您的示例中,即使正在显示“ from”,仍然会显示“ createdBy”。如果没有发件人地址,则应仅显示“ createdBy”。
jonhobbs

是的,它不会删除dom中的元素。对于createdBy从何时隐藏,只需在条件中添加条件:jsfiddle.net/pGwRu/3
matko.kvesic 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.