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
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'm reading a great article on this in JavaScript. The author says that the following code is bad:
Cart = {
items: [1,4,2],
onClick: function () {
// Do something with this.items.
}
}
$("#mybutton").click(Cart.onClick);
He says that the click event doesn't know about the Cart object when calling onClick, therefore this.items won't be the [1,4,2] array that I expect it to be.
The author goes on to say that this code creates a closure and fixes it but I don't understand how the following code fixes the problem.
$("#mybutton").click(function () { Cart.onClick() });
1) In what context (if not Cart) does this thing we're in if we use the first example.
2) Why does the second example fix the problem?
Some good detail about this is given in "How does the “this” keyword work?"
But, the important part is that the value of this is determined when and by how the function is invoked.
By passing the method itself as an argument, accessing it from an object and invoking it become separate acts. This separation is how it loses track of the object it came from – Cart.
The invocation is performed by jQuery. And, for event handlers, it determines the value of this to be the referenced element (matched by $("#mybutton"), in this case):
When jQuery calls a handler, the this keyword is a reference to the element where the event is being delivered; [..]
Rather than passing the method itself, this provides an alternate, wrapping function for jQuery to invoke instead. Within that function's body, accessing the method and invoking it are combined in a single statement.
Having them combined, the language itself determines the value of this as the (last) Object before the function – Cart.
this is always context of the function call. This is why $("#mybutton").click(Cart.onClick); sends mybutton object to the function as this. In the second example you call Cart.onClick() in its own context; this is Cart.
You can fix first example like this: $("#mybutton").click(Cart.onClick.bind(Cart)); to force context to Cart object.
If you try <button onclick="Cart.onClick()... then this is windows object.
I hope my explanation helps you.
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.
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.