I have an input field, which has two event handlers bound to it.
Validate & AutoSave
Obviously I want to validate before I save. If validation fails, the "invalid" class is added to the input and autosave will check for that class before it proceeds.
This works well enough, but is there a way to guarantee Validate runs before Autosave in all cases?
If you use JQuery to bind your events, it guarantees that handlers are fired in the same order that they were bound. Otherwise the order is officially undefined.
If you cannot use JQuery or a similar framework you can easily simulate this by using your own custom even binding, where your generic handler is a function which keeps an array of functions and calls them in order.
Normally you'd have the Save event handler call Validate() which will return true if everything is fine and ready to be saved.
function onSaved() {
if (!validate()) {
// set class
return;
}
// do the save
}
Why not attach just one handler -- Validate -- and call AutoSave from inside it?
For an answer to your question that isn't also a question, see this post or this one or this one.
Already answered - but just to add this piece of knowledge, the order of event handlers can not be relied upon. It may in any given implementation be predictable, but this can change from one (Javascript) implementation to the next and/or over time. The only thing certain is that they all will be executed - but not in what order.
Note that the situation is similar when there is an event handler for a DOM object and another one for the same event for a child or parent - which of those is executed first is not always clear as well. See http://www.quirksmode.org/js/events_order.html
Related
If I have multiple functions passed to a click event i.e.
#click="
inputHandler();
sendToken(computedUser.email);
responseMessage();
"
The function with an event parameter:
inputHandler(e) {
// code
}
Won't run. If I pass it on it's own:
#click="inputHandler"
It works fine.
Why is this and how can I get around it?
Internally Vue uses some RegExps to decide what form of event handler you're using.
If it seems to be the name of a method it will call it and pass the event.
If it seems to be inline code it'll just run it. In this case the event object is accessible as $event.
So:
#click="inputHandler($event)"
is roughly equivalent to:
#click="inputHandler"
Strictly speaking these aren't quite the equivalent, for example with component events that emit multiple arguments you'll only get the first one using $event like this.
See https://v2.vuejs.org/v2/guide/events.html#Methods-in-Inline-Handlers
For a deeper understanding see the Vue source code:
https://github.com/vuejs/vue/blob/0baa129d4cad44cf1847b0eaf07e95d4c71ab494/src/compiler/codegen/events.js#L96
Give your eyes a few minutes to adjust and it isn't too difficult to understand.
Personally I try to avoid anything more complicated than a single method call in the inline listener. Instead I'd suggest having something like #click="onSendClick" and let the method onSendClick worry about the details.
If I recall correctly, vue creates a wrapper function, if the passed value isn't a function. So
inputHandler();
sendToken(computedUser.email);
responseMessage();
actually get's turned into
function wrapper(){
inputHandler();
sendToken(computedUser.email);
responseMessage();
}
And as you can see the arguments passed to wrapper are lost.
The easiest way to fix this is probably to create a new method that accepts the event parameter and calls all of your function and use that one in the event handler.
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.
When programmatically triggering a change event in Jquery after updating the value, you can do either
$("input").val("A").change();
or
$("input").val("A").trigger("change");
Is there a reason to use one over the other. Are there any situations in which is more suitable than the other?
They are exactly the same. change() - and all the other shorthand event methods - uses trigger('change') internally (source).
In this specific case the only reason to choose one over the other is your preference of the semantics.
Under the hood calling change() ends up calling trigger('change') anyway. But also with trigger you can limit the call to a namespaced event handler for that event (e.g. trigger('change.myplugin')), so I just prefer to stick with trigger every time.
They have the same functionality, but are not exactly the same. So here is the source code for change():
function (a,c){
c==null&&(c=a,a=null);
return arguments.length>0?this.on(b,null,a,c):this.trigger(b);
}
So change() has a conditional statement which calls trigger('change') as a result of it. Thus, trigger('change') works slightly faster.
Instructions:
make this code work without modifying snippet it in any way.
Use only plain old JavaScript and no third-party libraries.
Write new code that enables the code below to work properly.
Hint: Feel free to extend native objects... even though it's typically a bad practice.
// Start with an object, any object
var myObject = {};
// Register an event on your object using
// an `on` method
myObject.on('myEvent', function(data) {
// Log the data passed to the callback
console.log(data);
});
// Trigger the event using a `trigger` method.
// Include some data when you trigger the event.
myObject.trigger('myEvent', {
company: 'ABC Corp',
location: 'WTC Bangalore, IN',
website: 'http://abc.co'
});
// Register a different event
myObject.on('yourEvent', function() {
console.log('yourEvent fired');
});
// Trigger the new event
myObject.trigger('yourEvent');
// Trigger all existing events using a special
// "star" identifier.
myObject.trigger('*');
// Remove one event by name
myObject.off('myEvent');
// Since we've removed the event, this should
// do nothing
myObject.trigger('myEvent');
// Remove all existing events
myObject.off();
// Since we've removed all events, this should
// do nothing
myObject.trigger('*');
Everything else went well. I'm unable to get "arguments" while implementing myObject.trigger("*"); unable to read arguments object / parameters while implementing "*" and hence throw undefined.
My JSFiddle
Disclaimer
I obviously dont know what school you go to or anything, but please don't fool yourself trying to fool your teachers. With a few simple questions they'll know if you understand the material or not, and if you show up with a good answer but no knowledge to back it up, they will know what's up. I'm not accusing you of this, just a friendly word of advice of someone who has had good connections with his teachers after graduating last year ;)
So, how do we do this? Basically, you will have to add some functionality to the prototype of object, at least if you want this to affect all objects made afterwards. You can always create your own class and add the function to that prototype if you only want that class to have this functionality.
We need 3 functions added to the prototype, on, off and trigger of course. On top of that we add one extra property called events, initially an empty object.
You can look at the raw code for all these in the jsfiddle, I will only go through the structure and logic of the code here.
events will hold all the handlers (functions) associated with each event. When adding an event for the first time, we add a eventName property to the events object, the value for this property is initially an empty array.
on will find (or create) the array linked to eventName in events, and push the function into the array (note we do not call the function at this time, we simply store the reference to the function in the array).
off will iterate the array of eventName, and if it finds the same function (note the ===), remove it from the array.
trigger will iterate the array of eventName and call each function. Note that the function is called with the this keyword in the function set to the object, and with the same parameters as the trigger function was called (except eventName, the first parameter, which is filtered out). Yes that means you can pass as many parameters as you want to trigger(), and they will all be passed to each handler.
I won't go into detail what things like splice, slice, ===, arguments and apply do exactly, I'm sure you can find more and better information about that elsewhere on the world wide interwebs.
There's a lot more you can do for this, like making the events object invisible through some nice uses of scoping, but that wasn't part of the question so I didn't bother with that.
If you have any more questions after looking through this, feel free to ask. I also didn't test it extensively so if you find any bugs, let me know.
EDIT: I didn't read through the comments at first, but I now also added support for the '*' wildcard. Basically the functions now check for the wildcard and will iterate all eventNames on the event object when removing or triggering. You can also remove all functions for an event by not giving a function or by giving the same wildcard, but with an eventName.
EDIT2: had some bugs running the teacher's code, realized I forgot to check for hasOwnProperty while iterating. Look that one up, it's very important when working with prototypes!
I now put in the teacher's code in my jsfiddle, to show you that it works :)
jsfiddle with own code
jsfiddle with teacher code
EDIT3 - about the 'undefined' log.
The teacher's code calls .trigger 5 times, and you should see 4 console logs and as far as I can tell, they are all correct.Let me run through each trigger, and the subsequent console logs.
You add a handler to myEvent, which logs the first parameter
You trigger myEvent, with parameter => The parameter (the object), is
logged.
You add a handler to yourEvent, which logs a hardcoded
string.
You trigger yourEvent, no parameter => The hardcoded string is logged'
You trigger * with no parameter, all handlers run => undefined is logged, since no parameters were given, data in myEvent's handler is undefined. The hardcoded string is also logged
You remove the myEvent handler, trigger myEvent and confirm no functions are called
You remove all event handlers, trigger * and confirm no functions are called from any events.
I honestly don't know what you expected to happen on step 5, since you give no parameter, the data is assigned undefined, that's intended behaviour.
If you want to merge the data given in step 2 so it remains on the object, then instruct so in your handler. (for example, iterate all properties of data and add them to this, then log this). Right now you simply pass it data, it gets logged, and then thrown away. You can also add a parameter in step 5, and then all handlers will receive it (including the yourEvent handlers, but that one doesn't assign nor use it).
document.getElementById("myBtn").addEventListener("click", displayDate);
I want to disable a whole bunch of objects on the page, and then re-enable them later. Since some of them are tags rather than buttons, I disable them by removing their onclick attr. I've tried to store the old handler in a .data(), but unfortunately when I attempt to restore them with $(obj).attr('onclick',$(obj).data('onclick')), it calls the function rather than restoring it to the attribute. And if I try to store it in a different attribute instead of a data, it doesn't store the function, it stores the return value for the function.
Is there any way to accomplish this without re-writing every tag and every onclick handler on my page?
if( doEnable) {
$(obj).attr('href', $(obj).data('href'));
$(obj).attr('onclick', $(obj).data('onclick'));
$(obj).removeClass(EIS.config.classes.disabled);
$(obj).show();
}
else {
// Save the things you're going to remove
$(obj).data('onclick', $(obj).attr('onclick'));
$(obj).data('href', $(obj).attr('href'));
$(obj).prop("href", null);
$(obj).prop("onclick", null);
$(obj).addClass(EIS.config.classes.disabled);
$(obj).show();
}
By the way, this code seems to work fine in Chrome and Firefox, but only sometimes in IE8 and never in IE6. Unfortunately the client tests first in IE6.
$(obj).attr('onclick', ...
is ambiguous, has results that differ in different versions of jQuery and different browsers. It probably doesn't do what you want. You should avoid using attr on event handlers.
The problem is the disconnect between the onclick attribute and the onclick property. jQuery has tried to brush the difference between an attribute and a property under the carpet in the past, using attr to access both, but they're quite different. This was changed in jQuery 1.6, and partially reverted in 1.6.1, to widespread controversy, confusion and incompatibility.
For many properties, the values of an attribute and the corresponding DOM property are the same; for others, including all properties that aren't strings, they aren't. Event handlers certainly aren't: the property is a Function object, whereas the string attribute might be (a) the original string of the onclick="..." attribute in the HTML, (b) nothing (if the onclick was assigned from script to be a Function object) or (c) unavailable (in older IE).
To access the event handler Function property, use prop() in jQuery 1.6:
$(obj).data('onclick', $(obj).prop('onclick'));
...
$(obj).prop('onclick', $(obj).data('onclick'));
or just use plain old JavaScript which is actually simpler and more readable; jQuery wins you nothing here.
obj._onclick= obj.onclick;
...
obj.onclick= obj._onclick;
Either way this is not going to reliably ‘disable’ elements since they can (and very likely will, if you're using jQuery) have other event listeners registered on them, using addEventListener/attachEvent rather than the old-school event handler interfaces.
It looks like saving a function via .data() works just fine:
var f1 = function() { console.log('invoked'); };
$('a').data('func', f1)
var f2 = $('a').data('func'); // 'invoked' is not printed
f1 === f2 // true
so how are you storing the function via .data? if you're doing something like
a = $('a');
a.data('onclick', a.click()); // click handler is invoked here
then you're actually invoking the click handler(s) prematurely, and storing the return value with .data().
--edit--
it appears that .attr(function) invokes the passed function. This is a feature of jQuery. I'd suggest using jQuery's .click() method to attach the function as a click handler.
a = $('a');
a.each(function() {
this.data('onclick', handler_fn);
this.bind('click', handler_fn);
});
// later
a.each(function() {
this.unbind('click');
});
// even later
a.each(function() {
this.bind('click', this.data('onclick'));
});
What about binding the event in jQuery instead of setting the onclick attribute?
$(obj).click($(obj).data('onclick'));
Can we see the code that you use to set the data attribute?