Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS watching an expression

Tags:

angularjs

Say we have this expression

$scope.showButton = users.is_admin() && !document.is_provided;

And then in the same controller you have a button that updates the value of Document.is_provided:

<button ng-click="document.is_provided = true;">Provide document</button>

The problem is that $scope.showButton should now changed but it's not changing.

Updated: Plnkr showing simplified issue: http://plnkr.co/edit/Qk2jnHAmqsrNXSAjDYEk?p=preview

like image 998
Jad Joubran Avatar asked Dec 20 '22 02:12

Jad Joubran


2 Answers

I'd like to add on to squiroid's answer and explain to you why it works. I'll provide a very simple way for you to understand, as this was a very common problem for me too when I started.

Angular has something called a Digest cycle. It is a series of functions that are called successively to make sure that if a variable A is two-way bound to another variable B (using ng-model for example), they always stay in sync (that is, always have the same value). Functions that angular provides (or services, that usually start with $, like $timeout etc), automatically start the digest cycle

So let's say that you have a variable A and you've bound it to the $scope variable B, which is equal to a variable C. You would expect C to be bound to A too, right? Because you think when you change C, B should change, and so, A should change too. But that is only possible when you start the digest cycle. The cycle will look for variables that need to be updated, and will update them. However, by simply changing the value of C, you will never trigger the digest cycle, and so your change will never propagate to A.

What you do when you put a variable in $watch is (as the $ suggests), you forcefully start a digest cycle. So now when you change C, you start the cycle, it tracks down that it needs to update A too, and that's why it works.

In your example, $scope.showButton is bound to document.is_provided. Now you're using a non-angular function to change the value of document.is_provided. This means that you do not trigger the digest cycle, and that means your change will never be propagated to $scope.showButton. Therefore, showButton always remains false.

And of course, an example to help you understand: http://jsbin.com/vojoso/edit?js,console,output

Watch the console. I've added logs to help you understand. Comment out the $watch statement and see what happens. Try understanding it and then doing it yourself, you'll get it.

Hope I helped :)

like image 69
siddhant Avatar answered Jan 06 '23 21:01

siddhant


I am not sure but you can watch on it:-

$scope.$watch(function(){
    return Users.is_admin() && !Document.is_provided;
},fuction(newVal){
$scope.showButton =newVal;
});

Hope it helps :)

like image 39
squiroid Avatar answered Jan 06 '23 20:01

squiroid