I noticed that methods get called automatically whenever the underlying $scope variable changes.
$scope.getLength = function() {
return $scope.length;
}
My html looks like the following
<div class="test">{{getLength}}</div>
Whenever I change $scope.length, the method updates the value on the UI. I know that variables get updated because of the MVVM binding in Angular. WHy does a method get called?
It is a binding is this case too; just a binding to a function. AngularJS updates all bound elements whenever it goes through a digest cycle.
Angular does invoke those bound function everytime the scope is getting changed, no matter if this $scope.length changed or any other scope variable.
But be careful with binding too much functions into scope like this... console.log something in the function and you will see.
working on enterprise angularjs app, binding functions within big scopes can cost like 5 % of cpu power invoking bound functions containing big calculations.
Related
I am facing the problem with one of my custom directives.I am passing a function from view(html) as the isolated scope local property(&) but the function doesn't get triggered/called. I have already tried one of the suggestions - which is to use object literal and pass it to the function that is getting triggered but that didn't worked.
My best guess is that it's the problem with the scope it check that the following function gets returned.
function(locals) {
return parentGet(scope, locals);
};
And the scope here is referring to nested scope and the function I want to access/trigger is in parent scope.
How can I access the parent scope in this custom directive? Or is there a way to tackle this problem?
thanks
I have a problem in Angular where I have a function declared in my controller and I want a directive to be able to call this function. I use the & in the directives scope to reference the parent function.
The problem occurs when there is another directive inside the first one and the inner directive also references this function in the controller.
The function can be called from within the first directive and the second directive (if the function has no arguments). The function can be called from the first directive and NOT from the second directive (if the function has arguments).
This plnkr shows it in action:
https://plnkr.co/edit/8E5oNvWcF0QQWL7pmxrD?p=preview
Is this a bug or am I missing something?
<directive-two increment="increment()" add="add({amount : amount})"></directive-two>
https://plnkr.co/edit/WvVcNIOJ8zKvFmchOQ5R?p=preview
If you are passing functions you have multiple options, i recommend you to check this article http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-3-isolate-scope-and-function-parameters
I updated your plnkr with my favourite option, storing a function reference and invoking it, first you must reference the function on the directive without adding the parenthesis after the function name as shown next:
<directive-one increment="increment" add="add"></directive-one>
Then you can invoke the function like this:
'<button ng-click="increment()()">Increment</button>' +
'<button ng-click="add()(5)">Add</button>' +
I prefer this option over send the json object, i think that is cleaner.
https://plnkr.co/edit/Y3OJpMfcp5R05a8uk1av?p=preview
From the hitch hiker's guide to directive, light bulb example,
scope.$watch(function() {
scope.bulb = controller.getState();
});
First parameter of $watch is a function, what is exactly being watched here?
I read another SO's post on scope, this is the explanation.
"The first parameter of the $watch method (the "watchExpression") can be either an Angular string expression (that is evaluated against the $scope), or a function, which is called with $scope as the first parameter."
I am still not clear about the use of function as a first parameter to $watch, from light bulb example
- is scope implicitly passed as a parameter to that function?
- does that function implicitly return scope.bulb, so scope.bulb is being watched?
No, the function is being watched. This means the function is called and its value checked against the value it returned last time at least once every apply-digest cycle! The scope is indeed passed, but not used in your example. HTH
P.S. It is a bit odd to use a watch expression to set a value on the scope. What the watch expression function should do is return the state and set the scope value in the callback. That means it is only set when it changes rather than every time it is checked. Odd example!
To me, this looks like a wrong usage of $watch. The function should return a value, which would be watched for changes, but in this case, it will always be undefined, so a change of the value will never be watched.
A better approach would be something like this:
scope.$watch(function() {
return controller.getState();
}, function(newVal) {
scope.bulb = newVal;
});
This would watch for changes of controller.getState(), and would assign the new value to scope.bulb whenever it changes.
This is an idiom to be notified whenever $digest is called. From the documentation, see the doc for $watch:
If you want to be notified whenever $digest is called, you can register a watchExpression function with no listener. (Since watchExpression can execute multiple times per $digest cycle when a change is detected, be prepared for multiple calls to your listener.)
I'm having an issue with binding an input from inside a view. I thought it would bind to the controller scope, but it seems to be binding to a child scope, so it's not updating above.
Other items will bind like I expect if they're inside an ng-repeat (I'm not sure why).
Here's an example:
http://jsfiddle.net/hMpsB/1/
What's the best way to bind the input to the correct scope if it's not inside an ng-repeat?
In your example you will have better luck binding your $scope.test to an object instead of a primitive type like this:
$scope.test = { val: "test value" };
You can see this fiddle for a working example.
The child scope that gets created in the ngView will copy your value and since your original $scope.test is a primitive string it has no link to the parent value so your input will be modifying the child scope copy. When binding to an object your child scope has a copy of the object reference but will ultimately modify the same instance of the object.
You can take a look at this question for more information on creating a service to persist data across multiple controllers (which is a little similar to your question).
You can also look into using $parent as described in this answer though as Mark mentions it's undocumented and might get messy if another child scope ever gets introduced somewhere.
I'm looking into the code of the jQuery ToolTip plugin(hereinafter Tooltip), and have a noticed a behaviour I don't fully understand.
Tooltip binds a mouseover function like so:
.mouseover(save)
When called in this way, this variable is HtmlDivElement.
I tried changing the mouseover to this:
.mouseover(function(e){save(event)})
Since I'm looking for the MouseEvent. However, now this variable is Window.
I found a way to baypass this and get the HtmlDivElement by using this line of code:
.mouseover(function(e){save(this, event)})
and using this as a replacment for the this inside the function.
My question is - why is the save function losing it's scope when being called inside an anonymous function inside the mouseover binding?
The value of this is established upon each function call. When your anonymous function calls that "save" function, it's not doing anything to establish what this should be, so it's the default value: the global object ("window").
You can do this:
.mouseover(function(e){ save.call(this, e); })
to make this take on the value you need. The this value in the handler will be arranged by the framework, so by using .call() you're passing it on to the "save" function.
To repeat: in JavaScript, this is not determined by static structure of the code. Instead, it depends on the situation of each individual function call. That means that for any function, no matter how it's declared, the value of this may be a complete surprise on any given function call.