为什么ngIf的优先级高于{{}}(插值)?

时间:2014-04-24 10:12:20

标签: angularjs

ngIf优先级(600)设置为高于{{ }}(100)的原因是什么?它的优先级是否不足以在{{ }}属性值中ng-if允许?

我想在$scope变量中包含一个条件:

控制器:

app.controller('MainCtrl', function($scope, $http, $parse) {
  $scope.hide = "check === 'hidden'";
  $scope.parsecond = function (cond) {
    return $parse(cond)($scope);
  };

});

模板:

  <body ng-controller="MainCtrl">
    <div ng-if="!{{hide}}">funky ng-if div</div>
    <div ng-hide="{{hide}}">ng-hide div</div>
    <div ng-if="!parsecond(hide)">ng-if div</div>
    <input type="input" ng-model="check" />
  </body>

ng-hide工作正常,因为它解析了hide变量的内容并返回&#34; check ===&#39; hidden&#39;&#34;然后由ng-hide指令进行评估。

ng-if尝试在插值有机会解析字符串之前评估{{hide}},因此ng-if会抛出异常。

我发现的唯一解决方案是调用一个基本上完成interpolate指令工作并返回解析内容的函数。

Plnkr显示问题:link

修改

阅读完文档后,我发现更好的方法是在$scope上不需要自定义方法,因为angularjs已经有一个方法可以根据当前$scope解析变量( $eval)。

所以我的解决方案是:

  <body ng-controller="MainCtrl">
    <div ng-if="!$eval(hide)">funky ng-if div</div>
    <div ng-hide="{{hide}}">ng-hide div</div>
    <div ng-if="!parsecond(hide)">ng-if div</div>
    <input type="input" ng-model="check" />
  </body>

更新了plnkr:link

虽然这仍然无法解释为什么ngIf具有更高的优先级。

编辑2:

只是让人们明白它不一样:

例如:

控制器:

$scope.value = "hi";
$scope.condition = "value === 'bye'";

HTML:

<div ng-hide="condition"></div> <!--This will be evaluated to true since !!"value ==='bye'" = true. -->
<div ng-hide="{{condition}}"></div> <!--This will be evaluated to false since value !== 'bye' = false -->
<div ng-if="condition"></div> <!--This will be evaluated to true since !!"value === 'bye'" = true. -->
<div ng-if="{{condition}}"></div> <!--This will give an exception since ngIf directive ran before interpolation directive in the $compile step. -->
<div ng-if="$eval(condition)"></div> <!--This will be evaluated to false since value !== 'bye' = false. -->

我的结论是,如果您希望指令在字符串中而不是在作用域上的属性中评估/设置监视,则使用$parse会更安全。虽然我可以{{ }}使用ng-hide / ng-show或任何优先级低于100的指令,但我猜测它是正确的。不安全,因为我依赖于编译顺序,并且它不是100%明确表示它在未来的补丁中不会发生变化。

2 个答案:

答案 0 :(得分:5)

ng-if期望其值是一个角度表达式 - under the hood它只使用$scope.$watch。因此,如果您想在范围内定义的某些变量(包括:ng-if)中包含scope.hide的内容,则将ng-if="hide"添加到您的标记中。这里没有双花括号。

现在回到你的问题:ng-if的优先级为600$interpolate是角度服务,而不是指令。因此$interpolate没有定义优先权。你从哪里得到100

更新

您可以通过添加标记ng-if,随时在某些功能(包括scope.conditionFn)中包含ng-if="conditionFn()"的内容。

更新2

我更新了您的PLNKR以使其正常运行。 您的plunker中ng-ifng-hide之间的不一致与$compile中发生的插值优先级无关。

更新3

看起来你是正确的插值顺序在这里起作用,但是......我真的看不到在angular的表达式内插入任何好的理由。 ng-if具有相对较高优先级的原因是它从/向DOM移除/添加了被转换的内容,而ng-hide只显示/隐藏了被转换的内容。我认为一个指令似乎可以工作而另一个指令是一个纯粹的巧合。 但是如果你不使用不必要的,多余的技巧,按预期工作,我的plunker会显示。

答案 1 :(得分:0)

要理解它为什么这样做,请观察this sample here的控制台,其中自定义指令(类似于ngIf)此时位于优先级0.该指令旨在删除元素,无需等待,将其添加回来。然而,您会看到一个错误,该错误是由于尝试将属性设置回transclude: element所导致的遗留而导致的错误,在这种情况下,ngIf只是一个标记,元素已经以评论的形式出现。

为了避免这种情况发生,ngIf通过提高优先级terminal:true并通过直接监控其直接从$tAttrs抓取的表达式来提前终止该过程。插值将执行,但这是在稍后阶段完成的,通过在ngIf表达式变为真的时刻调用转换函数,在原始元素的克隆上,现在在其控制之下。新元素将在评论元素下显示出漂亮和花花公子。

Here is the same sample but fixed。避免了错误情况。