I want to load a function on click event using $.proxy.
If i load the function using the below click event then everything works fine.
click event which is working
$('element').click($.proxy(this.doProcess, this));
click event which is not working
$('element').click(function(){
// Perform other things
$.proxy(this.doProcess, this);
});
As you can see that i want to perform other things on the click event before loading the function. Can you please help me figure out why it is not loading if i use ".click(function()..." instead of simply '.click()..'
Because in the first snippet the click function calls the returned function. In the second snippet you are binding the current this value to the function, but you don't call the returned function. You can use the invocation operator (()) for calling the function:
$.proxy(this.doProcess, this)();
Note that this in the context of the anonymous function (which is the current event handler) doesn't refer to the this keyword's value of the outer context, you can cache the value:
var that = this;
$('element').click(function() {
// Perform other things
$.proxy(that.doProcess, this)(/* arguments go here */);
// | |
// | ----- refers to the clicked element
// ----- reference of the outer context's `this` value
});
Related
Playing around with the .on('click', ) event and I get differing behaviour based on whether I supply an anonymous vs named function (the named function doesn't work). Is this a syntax error?
<div id="myID"> abc </div>
<script>
$("#myID").on('click',function(e){
console.log(e.type);
}); //works
function handle(e){
console.log(e.type);
}
$("#myID").on('click',handle(e)); //doesn't work
</script>
You need to replace
$("#myID").on('click',handle(e));
with
$("#myID").on('click',handle);
When you call a function, it is executed immediately. This happens when you do
$("#myID").on('click',handle(e));
You call the function, passing an event e which does not exist yet. What you want instead is giving jQuery a function that it should call when the user clicks on the element with the id myID.
This is possible in JavaScript because it has first-class functions. This means that if you create a function like this:
function handle(e){
console.log(e.type);
}
then you get a reference to the function that you just created. This reference is stored in a variable named handle. You could achieve the same if you do:
var handle = function (e) { // create a function and store a reference to it in a variable
console.log(e.type);
};
The function takes an argument e. This doesn't exist yet, it has to exist in the moment you call the function:
handle(e); // ReferenceError: e is not defined
You can pass the reference to that function to jQuery, which then calls your function when the user clicks the element. At that point, e still doesn't exist, because it will contain information about the event, which hasn't occured yet. It will look like this:
$("#myID").on('click', handle); // pass a reference to the handle function to jQuery
Now, handle doesn't get called, because you only pass a reference to the function. You could say that you pass the function as an argument to another (jQuery) function. This is called a callback function.
Edit
Note that all functions that were created above take e as their argument. The argument doesn't have to exist in the very moment you create the function. However, when you (or jQuery) call the function, you have to provide an argument so that the function can do its job.
It's the same with an unnamed function: you create the function, but the argument does not exist yet. When you (or jQuery) call the function, you have to provide an argument.
This means there is no essential difference. The only difference is that one function has a name, the other one doesn't. You could even do this:
$("#myID").on('click', function handle (e) { // pass a reference to the function, but do not call it
console.log(e.type);
});
... which has the same effect as:
$("#myID").on('click', function (e) { // pass a reference to the function, but do not call it
console.log(e.type);
});
... except that in the first example, you keep a reference to the function that you created in a variable called "handle". In the second example, you lose the reference to the function, and only jQuery will be able to use your function.
Edit end
Another example for that would be:
var testFunction = function (arg) {
console.log('My argument is:', arg);
};
var executeTwoTimes = function (callback) { // accept a callback function as the first argument
callback('foo'); // execute the callback function
callback('foo');
};
executeTwoTimes(testFunction); // pass a reference to testFunction
// or:
executeTwoTimes(function (a) { // pass a reference to an anonymous function
console.log(a + ' bar');
});
I hope I could make things clearer for you.
Im trying to add an event listener to a object for example:
this.startLoading = function(){
this.a.addEventListener("complete", this.loadingHandler()); this gives me an error
},
this.loadingHandler = function(){
console.log("im doing something")
}
ERROR: "Uncaught Error: addListener only takes instances of
Function. The listener for event "complete" is "undefined"
However if I put the loadingHandler() function inside the scope it works, for example:
this.startLoading = function(){
var loadingHandler = function(){...}
this.a.addEventListener("complete", loadingHandler()); // this works
},
Im not sure what instances of a function means in that regard?
When you put () after a reference to a function, that means to call the function, and the value of the expression is whatever the function returns.
Your second example, that you say works, actually will not work, and you'll get the same error if the "startLoading" function is called.
Because you probably need to retain the proper context (this), what you probably need is
this.a.addEventListener("complete", this.loadingHandler.bind(this));
The .bind() method returns a function (exactly what addEventListener requires) that in turn will invoke your function such that this has the value requested.
I have written two functions in JavaScript code as follows
Manager = FormManager.extend({
First: function () {
var response = this.Second("Feature"); //I'm able to get the alert
//I have added a click event handler
$('#element').on('click', function(){
var newResponse = this.Second("Bug"); //The alert is not poping
});
}
Second: function (type) {
alert(type);
//Performs certain operation
}
});
Error: Uncaught TypeError: Object #<HTMLButtonElement> has no method 'Second'
I also tried without using this keyword like:
Second("Bug") // Error: There is no method
Whereas this a simplified format (in-order to show a simple example) on my program that I'm playing with. I'm struggling to find out the reason.
Can someone direct me to the right path?
You are using incorrect this. try this way. this inside the handler represents #element not the context of the function itself.
var self = this; //cache the context here
$('#element').on('click', function(){
var newResponse = self.Second("Bug"); //Access it with self
});
Also i think you are missing a comma after First function definision and before Second function.
Fiddle
The reason being the callback you give gets invoked from within the context of the element so your this context changes. this context refers to the context from where the callback was invoked. But there are other ways to get around this like using $.proxy while binding your callback with jquery, using EcmaScript5 Function.prototype.bind etc. But ideally you don't want to do that because most of the cases you would need the context of the element there inside the handler.
Every time you use the this context variable in a function you have to consider what its value is.
Specifically that value will be whatever value the caller specified, whether by using myObj.mymethod(...), or mymethod.call(myObj, ...), or mymethod.apply(myObj, [ ... ]).
When your anonymous function $('#element').on('click', ...) is invoked jQuery will set the context to the HTML DOM element - it's no longer referring to your object.
The simplest work around is to obtain a copy of this outside of the callback, and then refer to that copy inside the closure, i.e.:
var that = this;
$('#element').on('click', function() {
// use that instead of this, here
console.log(this); // #element
console.log(that); // your object
});
Another method is using Function.prototype.bind:
$('#element').on('click', (function() {
console.log(this); // your object
}).bind(this));
or with jQuery you can use $.proxy for the same effect, since .bind is an ES5 function.
I actually prefer the var that = this method, since it doesn't break the jQuery convention that this refers to the element associated with the event.
What is the proper way to accomplish the following:
$("#btn").click(function1);
Calling the function:
function function1 (event) {
event.preventDefault();
}
This seems to work, however I don't understand how function1 understands what the event argument is referring to without it being passed in. Wouldn't a listener set up like this make more sense:
$("#btn").click(function1(event));
Here is a fiddle.
The .click() function in jQuery except as first parameter a function. In Javascript function are value, as well as a primitive value or an object. Functions are first-class citizens.
If you use function1(event) as a parameter, the function will be executed, because this is the semantic of the brachet after the function name. So the .click() jQuery function will receive the output of the function, which is not the expected type.
Passing the function name as a parameter means that you are passing the function (actually, a reference to the function), not the result of the function invocation. And the function will be called when the click event will be triggered. The function in this case is called "callback".
Callbacks are very importants in Javascript, since the event-driven behaviour is the main reason for using a client-side scripting.
The concept behind the callback system is
//the click function
function doSomething(callback){
//in your case the event is the argument that jQuery will prepare for you
var argument = produceTheArgument();
//doSomething is in charge to invoke the function, passing the argument
callback(argument);
}
//your function
function myCallback(argument){
//your function will consume the argument
}
//my callback is passed as a reference, not invoked
doSomething(myCallback);
you are subscribing to event and passing a reference to the function inside click listener - the jQuery event processor will just call your function in jQuery's context and will pass all parameters to it.
In your first example function1 knows that the event variable is, because JavaScript (and subsequently jQuery) passes the event information as a parameter.
This is the nature of JavaScript, not just jQuery. Consider the following:
document.getElementById('btn').addEventListener('click', function1, false);
function function1(e)
{
console.log(e);
}
JavaScript automatically calls function1 when #btn is clicked, and it automatically adds the event information as the first parameter. jQuery simply passes this information into its own methods as well, so that you have access to it.
According to jQuery's documentation:
The click event is sent to an element when the mouse pointer is over the element, and the mouse button is pressed and released. Any HTML element can receive this event.
Reference: http://api.jquery.com/click/
In traditional event registration model:
function foo(e){console.log(e.type)}
document.getElementById("#id").onclick=foo;//registered event handler
But in inline event registration model:
<a href="#" onclick=foo(event)>clck</a>
console.log(a.click)===function click(){foo(event)}
Can't event object be used directly within the function foo rather than pass as a function argument.Since event object being used within the click function is not passed by the browser we are manually passing it.Why passing event object within the event handler function dont work?
Since event object being used within the click function is not passed by the browser we are manually passing it.
That's not correct. The browser (at least W3C compatible browser) pass the event object to the event handler.
The equivalent to
onclick="foo()"
is
elem.onclick = function(event) {
foo();
};
The browser creates a function with event as first parameter and uses the value of the attribute as body of the function.
You have to pass the event object explicitly to foo because that's how JavaScript functions work. If you call a function inside another function, the outer function's parameters are not automatically passed to the inner function (that would be really confusing IMO).
Simpler example:
function foo(a) {
bar();
}
function bar(a) {
alert(a); // will show `undefined`
}
foo(42);