poshest
poshest

Reputation: 4237

AngularJS >=1.3: ng-if with one time binding that is removed when expression evaluates to true

I make heavy use of this trick

ng-if="::vm.isLoaded || undefined"

In this case, if vm.isLoaded is anything falsey the watch will continue to operate because undefined is always returned in that case, and the "one time binding" continues to watch until the expression evaluates to something other than undefined.

Is there any way to achieve the reverse? Ie keep watching truthy values until the expression evaluates to undefined, or some other "magic" value.

A real use case is a Loading... gif, which once the content is loaded, needs to disappear.

ng-if="!vm.isLoaded"

works fine (shows the loading gif while loading, and hides it once loaded), but once the stuff is loaded, I want the watch to be removed (the stuff will never become "unloaded" again).

Upvotes: 1

Views: 225

Answers (3)

gkalpak
gkalpak

Reputation: 48211

Copying over from GitHub:

Negative ngIf with one-time binding is indeed not possible currently and is a usecase (the only one afaik) that makes ngUnless (the opposite of ngIf) enable something that is not already possible.

A more verbose work-around for achieving what you want is to use ngSwitch (although this adds an extra DOM element - which you can hide of course).

<div ng-switch="::(foo || undefined)">
  <div ng-switch-when="undefined">
    This text will be removed for ever,
    once `foo` evaluates to something truthy
  </div>
</div>

That said, ngIf is just a plain old directive (and not a complex one for that matter), so it is not difficult to copy and modify its source code and include it in your app.

Here is an "ngUnless"-like demo.

Upvotes: 1

poshest
poshest

Reputation: 4237

ng-hide="::vm.isLoaded || undefined"

This doesn't directly answer the question, because I really wanted to use ng-if to remove the loading gif from the DOM altogether.

But hiding it and removing the watch is the next best thing. I'm not sure of the relative performance issue of accumulating dead hidden DOM elements vs accumulating dead watches.

What I really need is a negative version of ng-if. Like ng-notif. :P

Upvotes: 0

Sravan
Sravan

Reputation: 18647

$watch returns a deregistration function.

You can unregister a $watch with the function returned by the $watch call:

var unwatch = $scope.$watch('isLoaded', function(newValue, oldValue) {
    if(newValue == false || newValue == undefined)
    {
        unwatch();
    }
});

So, once your isLoaded becomes false or undefined, the watch on it is removed.

Upvotes: 0

Related Questions