Javascript Event Object - javascript

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);

Related

Calling jQuery event handler on click : anonymous vs named function behaviour

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.

How to add parameter to bound function created through .bind(this)?

I have added an event listener that points to a method of the current object. Because the context of this was lost, I binded the method. From what I understand, .bind(this) creates a new bound function, which means to remove the event listener, I have to keep the bound function in a variable for future use.
MyObject.prototype.addListener = function () {
var checkAnchorBound = this.checkAnchor.bind(this);
//anAnchorElement points to an anchor tag on the page
this.anAnchorElement.addEventListener("click", checkAnchorBound);
}
Now, whenever I click that anchor, checkAnchor runs and everything works perfectly. The problem is removing the event listener because that event listener needs to be removed inside this.removeListener which is called by this.checkAnchor. That means I cannot pass the bound function as a parameter.
MyObject.prototype.removeListener = function (event) {
//I cannot pass checkAnchorBound from MyObject.addListener as parameter
this.anAnchorElement.removeEventListener("click", checkAnchorBound);
}
I tried storing checkAnchorBound in the object so I would not have to pass the variable as a parameter like so:
MyObject.prototype.addListener = function () {
this.checkAnchorBound = this.checkAnchor.bind(this);
//anAnchorElement points to an anchor tag on the page
this.anAnchorElement.addEventListener("click", this.checkAnchorBound);
}
However, addEventListener no longer works. Is there a way to pass checkAnchorBound as a parameter even though my listener is a bound function? If not, is there a way I can store the bound function inside of MyObject?

calling a function using $.proxy javascript

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
});

How to pass the event argument of jQuery .click() to a non-anonymous function

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/

javascript scope, why does $(this) equal [window]?

I have an ajax function (not sure if relevant) that updates html and creates a few links:
click me
I'm not sure why, but onclick, if I alert $(this).attr('title') it shows as undefined, and if I alert $(this) it shows [window]
function column_click(){
value = $(this);
console.log(value);
thetitle= $(this).attr('title');
console.log(thetitle);
}
Does anyone know why this is the case?
This should fix the issue.
onclick="column_click.call(this);"
The reason is that your "click handler" is really just a function. The default is to have this refer to the window object.
In my example above, we are saying "execute column_click and make sure this refers to the a element.
You're confusing the obtrusive and unobtrusive styles of JS/jQuery event handling. In the unobtrusive style, you set up click handlers in the JavaScript itself, rather than in an onclick attribute:
$('.clickme').on('click', column_click);
The above will automatically bind this to the clicked element while the event is being handled.
However, this is not standard JavaScript! It's a feature of jQuery. The on method is smart enough to bind the function to the HTML element when it handles the event. onclick="column_click" doesn't do this, because it isn't jQuery. It uses standard JS behavior, which is to bind this to the global object window by default.
By the way, the reason you see [window] is that $(this) has wrapped window in a jQuery object, so it looks like an array with the window object inside it.
There are three main ways to deal with your problem:
Use unobtrusive binding: $('.clickme').on('click', column_click); in a script at the end of the page, or somewhere in the $(document).ready handler
Bind this manually: onclick="column_click.call(this)"
Avoid using this at all:
function column_click(e) {
var value = $(e.target);
//...
Of these, I'd strongly recommend either 1 or 3 for the sake of good coding.
You need to pass the parameter in the function of column_click,
click me
function column_click(obj){
value = $(obj);
console.log(value);
}
Note: this refer window object. so won't work what you expect.
A Short Overview of this*
When you execute a function in JavaScript, the default this is window.
function foo() {
console.log(this);
}
foo(); // => window
The this value can be changed in a number of ways. One way is to call the function as a method of an object:
var x = {
foo: function() {
console.log(this);
}
};
x.foo(); // => This time it's the x object.
Another way is to use call or apply to tell the function to execute in the context of a certain object.
function foo() {
console.log(this);
}
foo.call(x); // => x object again
foo.apply(x); // => x object as well
If you call or apply on null or undefined, the default behavior will occur again: the function will be executed in the context of window:
function foo() {
console.log(this);
}
foo.call(null); // => window
foo.apply(undefined); // => window
However, note that in ECMAScript 5 strict mode, this does not default to window:
(function() {
'use strict';
function foo() {
console.log(this);
}
foo(); // => undefined
foo.call(null); // => null
foo.apply(undefined); // => undefined
})();
You can also set the this by using bind to bind the function to an object before it is called:
function foo() {
console.log(this);
}
var bar = {
baz: 'some property'
};
var foobar = foo.bind(bar);
foobar(); // => calls foo with bar as this
Conclusion
You're using this code:
click me
Which means that when the link is clicked, it executes column_click();. That means the column_click function gets executed as a plain function, not a method, because (1) it's not called as a property of an object (someobject.column_click();), (2) it's not called with call or apply, and (3) it's not called with bind. Since it's not running in strict mode, the default this is window.
How to Fix Your Problem
Therefore, to fix your problem, you can simply use call (or apply) to tell the function to execute in the context of the element. Within the small code inside the attribute value, this refers to the element. So we can use column_click.call(this). It's that easy!
click me
However, it would probably make more sense just to pass the element as an argument:
click me
and change your function to accept the argument:
function column_click(el) {
// Use el instead of this...
}
* Getting Technical
this in JavaScript is dynamically scoped. This behavior differs from all other variables which are lexically scoped. Other variables don't have a different binding depending on how the function is called; their scope comes from where they appear in the script. this however behaves differently, and can have a different binding depending not on where it appears in the script but on how it's called. This can be a source of confusion for people learning the language, but mastering it is necessary in order to become a proficient JavaScript developer.
You're using jQuery right? Why not:
$(".clickme").click(function() {
value = $(this);
console.log(value);
thetitle= $(this).attr('title');
console.log(thetitle);
});
// or
$(".clickme").click(column_click);

Categories