In Javascript/jQuery what does (e) mean? - javascript

I am new to JavaScript/jQuery and I've been learning how to make functions. A lot of functions have cropped up with (e) in brackets. Let me show you what I mean:
$(this).click(function(e) {
// does something
});
It always appears that the function doesn't even use the value of (e), so why is it there so often?

e is the short var reference for event object which will be passed to event handlers.
The event object essentially has lot of interesting methods and properties that can be used in the event handlers.
In the example you have posted is a click handler which is a MouseEvent
$(<element selector>).click(function(e) {
// does something
alert(e.type); //will return you click
}
DEMO - Mouse Events DEMO uses e.which and e.type
Some useful references:
http://api.jquery.com/category/events/
http://www.quirksmode.org/js/events_properties.html
http://www.javascriptkit.com/jsref/event.shtml
http://www.quirksmode.org/dom/events/index.html
http://www.w3.org/TR/DOM-Level-3-Events/#event-types-list

DISCLAIMER: This is a very late response to this particular post but as I've been reading through various responses to this question, it struck me that most of the answers use terminology that can only be understood by experienced coders. This answer is an attempt to address the original question with a novice audience in mind.
Intro
The little '(e)' thing is actually part of broader scope of something in Javascript called an event handling function. Every event handling function receives an event object. For the purpose of this discussion, think of an object as a "thing" that holds a bunch of properties (variables) and methods (functions), much like objects in other languages. The handle, the 'e' inside the little (e) thing, is like a variable that allows you to interact with the object (and I use the term variable VERY loosely).
Consider the following jQuery examples:
$("#someLink").on("click", function(e){ // My preferred method
e.preventDefault();
});
$("#someLink").click(function(e){ // Some use this method too
e.preventDefault();
});
Explanation
"#someLink" is your element selector (which HTML tag will trigger this).
"click" is an event (when the selected element is clicked).
"function(e)" is the event handling function (on event, object is created).
"e" is the object handler (object is made accessible).
"preventDefault()" is a method (function) provided by the object.
What's happening?
When a user clicks on the element with the id "#someLink" (probably an anchor tag), call an anonymous function, "function(e)", and assign the resulting object to a handler, "e". Now take that handler and call one of its methods, "e.preventDefault()", which should prevent the browser from performing the default action for that element.
Note: The handle can pretty much be named anything you want (i.e. 'function(billybob)'). The 'e' stands for 'event', which seems to be pretty standard for this type of function.
Although 'e.preventDefault()' is probably the most common use of the event handler, the object itself contains many properties and methods that can be accessed via the event handler.
Some really good information on this topic can be found at jQuery's learning site, http://learn.jquery.com. Pay special attention to the Using jQuery Core and Events sections.

e doesn't have any special meaning. It's just a convention to use e as function parameter name when the parameter is event.
It can be
$(this).click(function(loremipsumdolorsitamet) {
// does something
}
as well.

In that example, e is just a parameter for that function, but it's the event object that gets passed in through it.

The e argument is short for the event object. For example, you might want to create code for anchors that cancels the default action. To do this you would write something like:
$('a').click(function(e) {
e.preventDefault();
}
This means when an <a> tag is clicked, prevent the default action of the click event.
While you may see it often, it's not something you have to use within the function even though you have specified it as an argument.

In jQuery e short for event, the current event object. It's usually passed as a parameter for the event function to be fired.
Demo: jQuery Events
In the demo I used e
$("img").on("click dblclick mouseover mouseout",function(e){
$("h1").html("Event: " + e.type);
});
I may as well have used event
$("img").on("click dblclick mouseover mouseout",function(event){
$("h1").html("Event: " + event.type);
});
Same thing!
Programmers are lazy we use a lot of shorthand, partly it decreases our work, partly is helps with readability. Understanding that will help you understand the mentality of writing code.

Today I just wrote a post about "Why do we use the letters like “e” in e.preventDefault()?" and I think my answer will make some sense...
At first,let us see the syntax of addEventListener
Normally it will be:
target.addEventListener(type, listener[, useCapture]);
And the definition of the parameters of addEventlistener are:
type :A string representing the event type to listen out for.
listener :The object which receives a notification (an object that implements the Event interface) when an event of the specified type
occurs. This must be an object implementing the EventListener
interface, or a JavaScript function.
(From MDN)
But I think there is one thing should be remarked:
When you use Javascript function as the listener, the object that implements the Event interface(object event) will be automatically assigned to the "first parameter" of the function.So,if you use function(e) ,the object will be assigned to "e" because "e" is the only parameter of the function(definitly the first one !),then you can use e.preventDefault to prevent something....
let us try the example as below:
<p>Please click on the checkbox control.</p>
<form>
<label for="id-checkbox">Checkbox</label>
<input type="checkbox" id="id-checkbox"/>
</div>
</form>
<script>
document.querySelector("#id-checkbox").addEventListener("click", function(e,v){
//var e=3;
var v=5;
var t=e+v;
console.log(t);
e.preventDefault();
}, false);
</script>
the result will be : [object MouseEvent]5 and you will prevent the click event.
but if you remove the comment sign like :
<script>
document.querySelector("#id-checkbox").addEventListener("click", function(e,v){
var e=3;
var v=5;
var t=e+v;
console.log(t);
e.preventDefault();
}, false);
</script>
you will get : 8 and an error:"Uncaught TypeError: e.preventDefault is not a function
at HTMLInputElement. (VM409:69)".
Certainly,the click event will not be prevented this time.Because the "e" was defined again in the function.
However,if you change the code to:
<script>
document.querySelector("#id-checkbox").addEventListener("click", function(e,v){
var e=3;
var v=5;
var t=e+v;
console.log(t);
event.preventDefault();
}, false);
</script>
every thing will work propertly again...you will get 8 and the click event be prevented...
Therefore, "e" is just a parameter of your function and you need an "e" in you function() to receive the "event object" then perform e.preventDefault(). This is also the reason why you can change the "e" to any words that is not reserved by js.

It's a reference to the current event object

this will be my first stackoverflow help but I am confident that my answer will help anyone reading this.
Basically, e is just an object containing information about the EVENT which has just occured.
if it is 'click', then the object will contain about the click,
if it is 'submit', then the object will contain about the submit,
and they are typically found in addEventListener.
clickMe.addEventListener('click', e => {
console.log(e)
}
meaning, whenever I 'click' the button, it will console.log the INFOMRATION about the event that happened which is I did is to 'click' it, this will print information about the click event.
e is very useful because you can access and use the event to your very own project such as printing the location of x value... like
clickMe.addEventListener('click', e => {
console.log(e.clientX)
}
then it will print the location where you 'click' that event.. mine it returns 32
if you prefer video, please watch this
https://www.youtube.com/watch?v=_BVkOvpyRI0
video is not mine
upvoting me will truly help me since I am a student and looking for opportunity to help here. Love lots!

$(this).click(function(e) {
// does something
});
In reference to the above code
$(this) is the element which as some variable.
click is the event that needs to be performed.
the parameter e is automatically passed from js to your function which holds the value of $(this) value and can be used further in your code to do some operation.

Related

JS > bind HTML onclick event to a Custom Element v1 object

TL;DR
How can I bind the callback of an inline onclick-event of a div element to the Custom Element, in which the div is placed?
I want to use onclick="foo('bar')" instead of onclick="this.foo('bar')".
Long version:
Having appended an Custom Element with a clickable div to DOM as follows:
<my-element>
<!-- 1. works -->
<div onclick="this.foo('bar')">click me</div>
<!-- 2. not working -->
<div onclick="foo('bar')">click me</div>
<!-- edit: 3. playground (works) -->
<div onclick="me.foo('bar')">click me</div>
</my-element>
... now I want to bind the foo()-function to my Custom Element (<my-element>).
1st solution: Here onclick calls a foo()-function on this (this.foo()), where this later gets bound to my Custom Element (see following code).
2nd solution: Here I want to omit this. and again bind it to my Custom Element. But: while the binding works in the above solution (1.), it does not without a prepended this. - that's my problem.
edited 3rd solution: Uses a Proxy to project the function call from me to this Custom Element. It doesn't solve the problem, but at least I tried.
So the problem is: How to get solution 2 working?
My Custom Element v1 class - including some code I tried:
class MyElement extends HTMLElement
{
constructor()
{
super()
}
connectedCallback()
{
var self = this
this.addEventListener('click', this.handleClick, true)
// Proxy for solution 3
window.me = new Proxy({},
{
get: function(target, prop)
{
return self[prop]
}
})
}
handleClick(ev)
{
console.log(ev.target.onclick)
// returns: ƒ onclick(event) { foo("bar") }
// > is typeof function
// provides the binding to "this" for solution 1
ev.target.onclick = ev.target.onclick.bind(this)
// call
ev.target.onclick()
// works on first solution
// throws error in 2nd solution: foo is not defined
}
foo(str)
{
console.log(str)
}
}
customElements.define('my-element, MyElement)
Some explanations:
Using addEventListener and setting its 3rd parameter (useCapture) to true, I capture the event before getting executed.
I'm able to log the foo()-function to the console. It is encapsulated in a callable function, which seems to be the reason, why I can't bind my context to the foo()-function itself.
Calling the function via ev.target.onclick() throws an error, as in the given context (window) no foo()-function exists.
Some thoughts:
React does something similar (I haven't used React yet), but I can't see how to transfer their solution, as they eventually somehow preprocess their onclick events (with eval?). That might be a reason why their syntax is onclick={foo} instead of onclick="foo()". I also don't know, if passing parameters is possible in React.
See: https://facebook.github.io/react/docs/handling-events.html
Referring to that, it might be a problem, that in my solution the foo() function is probably already somehow called inside the window context, what means, that it's context is already set and can't be changed anymore...? Anyways, trying to set onclick="foo" without brackets and calling it later doesn't work either.
Good read to this topic:
http://reactkungfu.com/2015/07/why-and-how-to-bind-methods-in-your-react-component-classes/
So, I don't know if there is a solution at all. Ideas or explanations are welcome anyways!
EDIT 2: Fixed.
It also works, when the element is created and appended from inside the element class:
var el = document.createElement('div')
el.innerHTML = 'click me'
el.onclick = () => {
this.foo('bar')
}
this.appendChild(el)
EDIT 3, 4, 5:
Played around a little (see solution 3) and assigned a Proxy object to a global variable ('me'), which projects any function calls to this Custom Element - kinda __noSuchMethod__. So... by choosing a 1- or 2-character-variable one could save at least a few hits on his keyboard by not typing this. but me., vm. or even i. ... best solution so far. Sad!
Unfortunately, solution 3 can also not be used as general pattern for all elements, as it bounds the context only to one (i.e. the last connected) Custom Element.
EDIT 6 - Preliminary conclusions
As it turns out, it seems not possible to bind a html-inline onclick-event (onclick="foo('bar')") to the Custom Element class, in which the clickable element is embedded.
So the most obvious ways to go to me would be:
A) use the this keyword (like onclick="this.foo('bar')") and bind it to the class as shown above. Why this.foo() is bindable whereas foo() without this is not, remains unclear at the moment. I wonder bc both functions do not really differ - both have already bindings: this.foo() is bound to the clickable element, foo() is bound to window.
B) use eval as suggested by #Supersharp, i.e. add an event listener to the Custom Element, listen for clicks, get the value of the onclick-attribute as string, prepend "this." to the string and effectively do this: eval("this." + "foo()").
C) alternatively to inline onclick, I would tend to use event delegation and use declarative html attributes to indicate behaviour. To do this, again add a click event listener to the Custom Element class:
myElement.addEventListener('click', function(ev) {
if (ev.target.dataset.action)
{
this[ev.target.dataset.action]()
}
}, false)
Your clickable element would look like <div data-action="next">Show more</div>.
A solution is to use eval() on the concatenation of "this." and the content of the onclick attribute the event.target element.
Don't forget to use event.stopPropagation() to stop dispatching the event.
handleClick( ev )
{
eval( 'this.' + ev.target.getAttribute( 'onclick' ) )
ev.stopPropagation()
}
If you don't want to use eval(), you should parse the content of ev.target.getAttribute( 'onclick' ) to extract the function name et arguments and then call the element method if it exists:
if ( typeof this.name === 'function )
this[name](arguments)
Update
I suggest that you give an id to the custom element, then call the id + method:
<my-element id="me">
<div onclick="me.foo('bar')">click me</div>
</my-element>
This way you don't need to redirect/catch the event, and the div can be anywhere in the element.

using $(this) to get data attribute doesnt return the actual result

Im new to javascript/jquery, I've been searching all over the web but haven't got a satisfying answer. (I will delete it if someone can point out a similar question)
In the hmtl I have
Submit
In the console, I tried this
$('.btn-place-order').data("confirm-modal")
--> it returned "myModal"
But when I tried
$(".btn-place-order").on("click", function(e){ $(this).data("confirm-modal"); });
--> it return the whole object [a.btn-place-order]
Why ?
This behavior is exactly correct. If you take a look at the jQuery documentation you will see:
jQuery on:
.on( events [, selector ] [, data ], handler(eventObject) )
Returns: jQuery
jQuery data:
.data( key )
Returns: Object
This means that when you call var myObject = $('.btn-place-order').data("confirm-modal"); will contain the value of the data- attribute.
However, when you call $(".btn-place-order").on("click", function(e){ $(this).data("confirm-modal"); }); you get a jQuery object returned. This jQuery object is the same one that $(".btn-place-order") already returns, which is very important to make jQuery's concept of chaining work.
Chaining allows you to execute several methods in order, without getting the original jQuery object over and over. For example $(".btn-place-order").on('click',...).on('hover',...); would allow you to attach two handlers (a click and a hover) to the same element.
It also wouldn't make sense for on to return anything else, since it just attaches a handler to an element. It really doesn't give you any value just because you attach an event handler.
Now, if you want to take any action when the event is fired, you will need to take that action inside of the handler's callback function. E.g.
$(".btn-place-order").on("click", function(e){ alert($(this).data("confirm-modal");) });
will alert the user of the data-confirm-modal attribute value of the element that was clicked on. However, without the alert() part (i.e. the way your original code was written), the value is just read, but nothing is ever done with it.

Where are attached event-handlers 'meta-data' stored? On the "DOM," object, or...?

I've always wondered... so you have a code like this:
$('#click-me');
and you attach it with this:
$('#click-me').click(someFunction);
where is the 'meta-data' that says:
"Hey "jQuery-object #click-me," I will point you to 'someFunction' when you are clicked!"
I know that event-handlers can get destroyed such as my situation with Backbone.js where my events stopped firing due to me re-rendering the entire page, destroying some background functions/objects/Views along the way.. (this is the context as to why I'm asking this question)
NOW, MY QUESTION IS:
where are events 'meta-data' stored and how are they destroyed?
Are they stored within the function that bound it to a function? Are they within the DOM 'meta-data' (if there is one) itself?
I'm trying to learn the intricacies of JavaScript because I'm tired of bugs. In addition to that, I'm wondering if I should watch out for garbage collection that might detach my events and such. Coming from C#, I would say JavaScript with the DOM is really something...
(also, as a side note, how can I access these events and 'debug' them? firefox? chrome?)
UPDATE
To say it in different words, where is the information that connects a DOM element to a certain event stored? DOM? Objects? (or.. does jQuery map it? does JavaScript have a 'meta-data'? it's around that context..
Update : So I misunderstood the question, you wanted to know how events are bound in the context of just javascript and html. My original answer below describes how jquery creates and manages events. It boils down to a call to element.addEventListener.
From the MDN docs you see the eventtarget can be an element, the document, window or an XMLHttpRequest. From the w3 specifications on DOM Events an event target adds, removes and dispatches an event. So even information is probably stored in whatever is encapsulating things like elements, this will be implemented at the browser level.
From the issue you mentioned about copying and then replacing the html from the body erases the events, I'm thinking the browser just gives you the markup (without the event metadata) and then when you replace it, the metadata is gone. ( http://jsfiddle.net/qu9bF/1/)
Original answer: How jquery event handlers work.
Ok so I started digging this, for JQuery 1.4.2 (because I had to use a couple tools, all of which aren't updated)
Take a look first at this:
http://james.padolsey.com/jquery/#v=1.4.2&fn=click
function (fn) {
return fn ? this.bind(name, fn) : this.trigger(name);
}
That is how click is defined, it isn't actually defined in code. JQuery defines this function for all events/handler functions like below, yes! they are created/defined dynamically :
jQuery.each( ("blur focus focusin focusout load resize scroll unload click
dblclick " +
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
"change select submit keydown keypress keyup error").split(" "),
function( i, name ) {
// the magic happens here..
//each string is added as a function to the prototype
jQuery.fn[ name ] = function( fn ) {
return fn ? this.bind( name, fn ) : this.trigger( name );
};//if a handler is NOT specified then attach an event OR call/trigger it
if ( jQuery.attrFn ) {
jQuery.attrFn[ name ] = true;
}
});
From here on we need to look at bind, now bind() and one() are also defined like this. Search for "Code : bind and one events" here
From here I used chrome with this fiddle http://jsfiddle.net/qu9bF/ to step into the code. The block from c.each(["bind" is how the bind function is defined. The source is minified, but chrome can format it.
From here on the code calls JQuery.events.add, you can find this under the Events section here. This is not the add() that is documented I think
Toward the bottom, this piece of code is what does the magic. It accordingly calls element.addEventListener or attachEvent. See how it adds the on for attachEvent.
// Check for a special event handler
// Only use addEventListener/attachEvent if the special
// events handler returns false
if ( !special.setup ||
special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
// Bind the global event handler to the element
if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle, false );
} else if ( elem.attachEvent ) {
elem.attachEvent( "on" + type, eventHandle );
}
}
And there you have it! :) I hope it answered both your questions. You can link up to the non-minified versions of jquery source and step through it to figure things out. IMO sometimes IE9's debugger is more intuitive (that's the only thing I use it for), and use the pages I've mentioned to browse through the source sanely.
jQuery stores all the event binding and data cache on the jQuery.cache object. All the DOM nodes which were wrapped with jQuery and had events bound to them or data set will get automatically cleared when you are using jQuery html, empty, remove, replace etc.
That's why it's very important to never use innerHTML or other native DOM methods to insert/replace content that was altered before by jQuery. It will lead to leaks that you won't be able to cleanup unless you reset the jQuery.cache object manually.
There is also an undocumented method jQuery.cleanData which takes a collection of DOM nodes as an argument and it iterates over them and cleans up all their event bindings, data and removes references to these elements from the cache. This one can be useful if you have DOM fragments which were detached from the main DOM tree and there is a risk that they won't get cleaned up properly.
Regular events like click or submit (when not bound by jQuery) are actually just properties ('onclick', 'onsubmit') of the DOM elements themselves.
For jQuery events, the library keeps it's own record when you bind them and looks at it when you trigger them. jQuery puts all data about elements in a standard place, which you can access with $(e).data(). For events, it's just $(e).data('events').
You can unbind jQuery events with $().unbind(), and regular events using the delete keyword to delete the object's property which corresponds to the given event.
jQuery keeps its own map of element event handlers. There's rarely, very rarely, cause to worry about this unless you're abusing the library somehow.

Jquery .change() to view currently assigned method

Is there any way I can view the current method assigned to a selects change event.
I have tried.
$('#select').change()
but that just returns me the change event. I don't really need to do this but would be very handy for debugging. Save me hunting through the code to find the method, this way I can simply search the text in the method and find the method quickly.
$('#select').data('events').change;
This will contain an array of objects, one per event handler.
If you're sure there's only one change event handler, you can access the function directly:
var theFunction = $('#select').data('events').change[0].handler;
See it here in action: http://jsfiddle.net/7UD3e/
A slight alteration to Joseph's answer will make the actual code for the function be output:
var clickEvents = $('#select').data("events").change;
$.each(clickEvents, function(key, handlerObj) {
console.log(handlerObj.handler) // prints actual function code, does not run function
})
Source: How to debug JavaScript/jQuery event bindings with Firebug (or similar tool)
Here is a demo: http://jsfiddle.net/7UD3e/2/

jQuery ".triggerHandler()" vs. ".trigger()" when multiple elements are selected

The jQuery ".triggerHandler()" mechanism, unlike ".trigger()", only operates on the first element referenced by the jQuery object for which it's called. In other words,
$('.all-over-the-page').triggerHandler("readjust");
will only call the "readjust" handler for the first element with class "all-over-the-page", even if there are many elements on the page with that class. The ".trigger()" method, on the other hand, would affect all of them.
I realize that I can use ".each()" to get around this (or simply write my own substitute that does that for me), but is there some rationale for why the two are different in this respect? It kind-of makes no sense to me. (I understand of course that it almost certainly can't be changed now.)
edit to clarify:
It's probably easier to understand why I'm scratching my head over this if I provide a context in the style of code I've actually got. When I put together code for various "widget" features on a page, that often involves event handlers. A good example is a form of some sort that's got some fields whose relevance is controlled by a checkbox, or radio button, or selector. A common instance of that is the "Shipping Address" checkbox that shows up on a zillion e-commerce sites: if the checkbox is checked, the shipping address is disabled and the billing address is used.
Now consider that some other code may, for its own reasons that are totally independent of the checkbox-control widget, actually do things to the form that may include updating checkbox settings programmatically. In that case, that other widget code may want to use "triggerHandler()" to tell any widgets, "hey I've updated some stuff, so you might want to re-check the current status and adjust if necessary."
Thus, if ".triggerHandler()" would operate on all selected elements, I could use:
$theForm.find('input, select, textarea').triggerHandler('change');
and all those handlers could run and do whatever they need. As I said, it's easy enough to write:
$theForm.find('input, select, textarea').each(function() {
$(this).triggerHandler('change');
});
"...is there some rationale for why the two are different in this respect?"
I think the idea is that triggerHandler() is meant to be a way of invoking the function you as a handler as though it was any other function.
As such, they made triggerHandler() so that the function is only invoked once, it returns the actual return value of the function, and it doesn't affect the DOM with bubbling or default behaviors.
Of course the function may break if they changed the this value to something other than a DOM element, so they just use the first element matched.
If you're wanting to simply use your function, then I'd probably just keep a reference to it and invoke it directly, or as the argument to .each().
$('.element').each( handler_func );
...as long as you don't need the event object.
EDIT: Or if you want the values returned from the invocation, use .map() instead:
var return_values = $('.element').map( handler_func );
EDIT: With respect to the example provided in the updated question, a good solution may be to take advantage of the extraParameters capability of the trigger()[docs] method so that you can tell the handler to preventDefault() and stopPropagation().
$('.elememts').bind( 'click', function( e, was_code_triggered ) {
if( was_code_triggered ) {
e.preventDefault();
e.stopPropagation();
}
// your code
});
// ...
$('.elememts').trigger( 'click', true ); // pass "true" to let handler know
// it wasn't a DOM event
From the .trigger() docs:
"Note the difference between the extra parameters we're passing here and the eventData parameter to the .bind() method. Both are mechanisms for passing information to an event handler, but the extraParameters argument to .trigger() allows information to be determined at the time the event is triggered, while the eventData argument to .bind() requires the information to be already computed at the time the handler is bound."

Categories

Resources