What is the reasoning behind setting ngIf
priority (600) higher than {{ }}
(100)? Shouldn't it have a lower priority to allow {{ }}
inside ng-if
attribute value?
I would like to have a condition inside a $scope
variable:
Controller:
app.controller('MainCtrl', function($scope, $http, $parse) {
$scope.hide = "check === 'hidden'";
$scope.parsecond = function (cond) {
return $parse(cond)($scope);
};
});
Template:
<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
works fine since it parses the contents of the hide variable and returns "check === 'hidden'" which then gets evaluated by ng-hide
directive.
But ng-if
tries to evaluate {{hide}}
before interpolate has had a chance to parse the string hence ng-if
throws an exception.
The only solution I've found is call a function that basically does the job of the interpolate directive and returns the parsed content.
Plnkr showing the issue: link
EDIT:
After reading documentation I've found better way of doing it without the need of a custom method on the $scope
since angularjs has already a method that parses a variable against its current $scope
($eval
).
So my solution would be:
<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>
Updated plnkr: link
Although this still doesn't explain why ngIf has higher priority.
EDIT 2:
Just so people understand that it's not the same:
For example:
Controller:
$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. -->
My conclusion is that it safer to use $parse
if you want the directive to evaluate/set a watch in the string rather than in the property on the scope. Although it's true that I could use {{ }}
for ng-hide
/ng-show
or any directive that has a lower priority than 100 but I'm guessing it's not safe since I'm depending in the compiling order and it's not 100% clear that it won't change in future patches.
ng-if
expects its value to be an angular expression - under the hood it just makes use of $scope.$watch
. Therefore, if you want to condition including content of ng-if
on some variable defined on the scope (let say: scope.hide
), you put ng-if="hide"
in your mark-up. No double curly braces here.
Now back to your question: it is true that ng-if
has priority of 600
, but $interpolate
is angular's service - not a directive. As such $interpolate
does not define priority. Where did you get 100
from?
You can always condition including content of ng-if
on some function (let say scope.conditionFn
) by putting in your mark-up: ng-if="conditionFn()"
.
I updated your PLNKR to make it working. The inconsistencies between ng-if
and ng-hide
in your plunker had nothing to do with priority of interpolation taking place in $compile
.
It seems that you are right that order of interpolation plays a role here, but... I really do not see any good reason to interpolate inside of angular's expression. The reason why ng-if
has relatively high priority is that it removes/adds transcluded content from/to DOM, whereas ng-hide
just shows/hides the transcluded content. I think it is a pure coincidence that one directive seems to work and the other not. But if you do not use unnecessary, superfluous tricks, both do work as intended, what my plunker shows.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With