I started web development recently, and i can't seem to wrap my head around event handlers and callback functions. I understand that events handlers are a type of callback, and they respond to events unlike the more general definition of callbacks that get called by some other code when it finishes running. But, I'm looking for an explanation that 'sticks' with me.
Here's an example
<script>
$(document).ready(function(){
$("button").click(function(){
$("p").hide("slow", function(){
alert("The paragraph is now hidden");
});
});
});
</script>
In this code example, i know that ready and click are both events so $("button").click(function(){ is an event handler for the ready event? and $("p").hide("slow", function(){ is an event handler for the click event? How about hide? is it also an event?
Yes, that's correct (took me a second to realize you were just showing the content of the handlers you were referring to). It's clearer if you don't define the handlers/callbacks inline, and you give them descriptive names:
function readyHandler() {
$("button").click(clickHandler);
}
function clickHandler() {
$("p").hide("slow", hideAnimationCompleteCallback);
}
function hideAnimationCompleteCallback() {
alert("The paragraph is now hidden");
}
$(document).ready(readyHandler);
Note that the code above is slightly different from your original, which looks more like this:
function readyHandler() {
function clickHandler() {
function hideAnimationCompleteCallback() {
alert("The paragraph is now hidden");
}
$("p").hide("slow", hideAnimationCompleteCallback);
}
$("button").click(clickHandler);
}
$(document).ready(readyHandler);
...but since none of the handlers/callbacks was relying on the fact it was created inside a handler/callback, it seemed clearer to show them completely independently. But it would matter if they were using something that's only in-scope within the handler they were created in.
Callback functions are what you described. Functions that are passed as parameters to another function and then later "called back".
Example:
file.read(fileName, function (err, data) {
// once file reading has finished, this function body is called,
// so this anonymous function is the callback
});
Event handlers are functions that gets triggered when a specific event occurs. It can be used for synthetic events, websocket events, and more. And its usual syntax is using callbacks.
Examples:
eventBus.on('new_message_arrived', function (err, data) {
// when 'new_message_arrived' event happens, this callback will be called
});
button.click((event) => {
// when button gets clicked, this callback (now used arrow function notaion)
// will be called with the details of the UI event
});
Related
I have a function in my controller that targets a button, then attaches an event listener, which should call a function on the click event but it is calling it automatically when the page loads.
How do I change this to only call the function when I click on goBtn?
onAfterRendering: function() {
var goBtn = document.getElementById('__xmlview1--smartFilterId-btnGo');
console.log("goBtn = ", goBtn);
goBtn.addEventListener("click", this._onGoClick(event), false);
},
_onGoClick: function(event) {
console.log("Event attaaaaached!!! = ", event);
// do something else
},
The problem is that you are already evaluating your event handler. This calls the _onGoClick method immediately (as soon as this line is reached).
goBtn.addEventListener("click", this._onGoClick(event), false);
What you want to do is pass a function to addEventListener that gets called later.
goBtn.addEventListener("click", this._onGoClick, false);
On a different note your code is meant to break in the near future. The id __xmlview1--smartFilterId-btnGo is dynamically created and can change as soon as you launch the app in a different context.
I have a custom event which I listen to:
$(document).on('MyCustomEvent', function(e, data) {
});
My problem is that I would like to know when MyCustomEvent has fired inside a lot of different functions. I don't want to attach the event handler inside each function, since it doesn't make any sense and will probably override eachother.
What I'm after is something like this:
function one(){
//"when MyCustomEvent is fired, do stuff with the 'data' here"
}
function two(){
//"when MyCustomEvent is fired, do stuff with the 'data' here"
}
What's the problem with attaching all these functions as event handlers?
$(document).on('MyCustomEvent', function(e, data) {
one(data);
});
$(document).on('MyCustomEvent', function(e, data) {
two(data);
});
You would of course need to change the signatures so that the functions accept data as an argument. I have attached the two functions separately because usually attaching handlers in a modular manner like this is the only way to go.
You could also use an event namespace so that you can detach the handlers independently of each other:
$(document).on('MyCustomEvent.one', function(e, data) {
one(data);
});
$(document).on('MyCustomEvent.two', function(e, data) {
two(data);
});
$(document).trigger('MyCustomEvent'); // both functions are called
$(document).off('MyCustomEvent.one');
$(document).trigger('MyCustomEvent'); // only two() is called
How do I clear out anonymous functions that are set to trigger via a jQuery document.ready() call?
For example:
<script type="text/javascript">
//some code sets a doc ready callback
$(document).ready(function ()
{
alert('ready');
});
//my attempt to prevent the callback from happening
window.onload = null;
$(document).unbind("ready");
</script>
The alert happens regardless of my attempts to circumvent it. Is there any way to do this?
You'd probably get the most appropriate answer if you described what problem you're really trying to solve.
jQuery doesn't have a publicly documented way to undo or block document.ready() handlers. If you control the code, you can use a global variable and a conditional like this:
var skipReady = false;
$(document).ready(function ()
{
if (!skipReady) {
alert('ready');
}
});
// skip the document.ready code, if it hasn't already fired
skipReady = true;
Or, if you want to hack into jQuery a bit (beyond the documented interfaces), you can do this:
$(document).ready(function() {
alert("ready");
});
// stop the ready handler
$.isReady = true;
You can see this last one work here: http://jsfiddle.net/jfriend00/ZjH2k/. This works because jQuery uses the property: $.isReady to keep track of whether it has already fired the ready handlers or not. Setting it to true makes it think it has already fired them so it won't every do it again.
This works:
$(document).bind("ready", function () { alert("hey!"); });
$(document).unbind("ready");
Seems like a bug to me - all other events in jQuery are able to be unbound. Omitting this one is inconsistent.
Not a direct answer as to the omission, but here's some related info from jQuery docs:
All three of the following syntaxes are equivalent:
$(document).ready(handler)
$().ready(handler) (this is not recommended)
$(handler)
There is also $(document).bind("ready", handler). This behaves similarly to the ready method but with one exception: If the ready event has already fired and you try to .bind("ready") the bound handler will not be executed. Ready handlers bound this way are executed after any bound by the other three methods above.
$(document).ready() is dependent on the onLoad event which is triggered by the browser meaning you can not prevent it from happening. If the alert() is determined by some condition then I would use an if/else statement to decide whether it is called.
Super old question, but came across the need to do this recently to prevent document.ready code I didn't control from running in certain instances. This can be achieved by proxying jQuery's ready function, rather like a test spy. The following will work:
var ready = $.prototype.ready;
// proxy the ready function
$.prototype.ready = function ( fn, allowed ) {
allowed = allowed || false;
if ( allowed ) {
ready.call( this, fn );
}
};
All calls to $( document ).ready will now be ignored. You can override this behaviour by passing true as the second argument: $( document ).ready( fn, true )
What is the difference between event handlers and event listeners in JavaScript? They both execute a function when the event appears.
I don't really get when to use event handlers and when to use event listeners.
A handler and a listener are one in the same - just synonyms for the function that will handle an event. "Handler" is probably the more accepted term, and is certainly more semantically correct to me. The term "listener" is derived from the code used to add an event to an element:
element.addEventListener('click', function() { /* do stuff here*/ }, false);
You could, however, get really nitpicky and break the two down into separate meanings. If you're so inclined, "handler" could be the term for the function that is going to handle an event when you add a "listener", thus one can have several "listeners" that utilize a single "handler". Consider:
// handler is synonymous with function
function someFunction(e) {
if (typeof e == 'undefined')
alert('called as a function');
else
alert('called as a handler');
}
// use someFunction as a handler for a
// click event on element1 -- add a "listener"
element.addEventListener('click', someFunction, false);
// use an anonymous function as a handler for a
// click event on element1 -- add another "listener"
element.addEventListener('click', function () { alert('anonymoose'); }, false);
// use someFunction as a handler for a
// click event on element2 -- add a "listener"
element2.addEventListener('click', someFunction, false);
// call someFunction right now
someFunction();
So in the above code, I have 2 "handlers" (someFunction and an anonymous function) and 3 "listeners".
Again, this is all semantics - for all practical purposes the terms listener and handler are used interchangeably. If a distinction need be made then a listener is a subscription to an event that will trigger a call to a handler (which is a function).
Clear as mud?
There's no difference; it's just different terminology for the same thing.
There are different ways of associating functions with DOM elements for the purpose of event handling, that's all. The differences emerged back when standards were in flux (or just because implementors were ornery or difficult) but ultimately the mechanisms are essentially the same.
If you're confused about what sort of event handler registration to use, you can:
Read more about the topic and choose an approach to use, perhaps on a browser-by-browser basis;
Choose one of the popular JavaScript frameworks and use its mechanism for attaching handlers
This site, (which funnily enough has a cyclical reference to here by one of the comments) states otherwise, to what people have answered here (stating they are same); pasting one of the answers:
One difference is that if you add two event handlers for the same button click, the second event handler will overwrite the first and only that event will trigger. For example:
document.querySelector('.btn').onclick = function() {
console.log('Hello ');
};
document.querySelector('.btn').onclick = function() {
console.log('World!');
};
// This logs "World!" out to the console.
But if you use addEventListener instead, then both of the triggers will run.
document.querySelector('.btn').addEventListener('click', function() {
console.log('Hello ');
});
document.querySelector('.btn').addEventListener('click', function() {
console.log('World!');
});
// This logs "Hello" and "World!" out to the console.
I find this explanation particularly hands-on:
Event handlers are comprised of an event listener and a callback function.
An event listener specifies the type of event that will be detected.
The callback function executes when the event happens.
Everything together is the event handler.
both of them used for associating a function when an event occurs, if using the event listener's you can listen more than once in A specified event (duplicate) for example listen to tow 'click' event into independent event listener's, but when using the handler it's impossible because handler is a property of your dom object and if Assign more than once a function in same event handler, for example, when set to the a element tow handler for onClick event, the last event handler assignment is work.
myElement= document.querySelector('#btn');
myElement.onClick = function(){
alert('first event handler');
}
myElement.onClick = function(){
alert('second event handler');
}
// result : occur last handler >> alert('second event handler');
but if using the event listeners you can listen to how many times listen to the same
event.
myElement.addEventListener('click',()=>{
alert('first listener')
})
myElement.addEventListener('click',()=>{
alert('second listener')
})
/* result : occur both listeners - alert('firstlistener') >> and next >> alert('second
listener'); */
there's no big difference.
we can say they are almost the same things except for three subtle things that are:
you can use an event handler once. if you use a handler to an element twice or more, then the last handler will overwrite all those previous handlers.
on the other hand, if you use event listeners more then once, there won't be such a thing like this.
you can use many event listeners, but not just one.
For some events, handlers only work with addEventListener. like the DOMContentLoaded event, which triggers when the document is loaded and DOM is built.
whit using event listeners, you can pass an object or class by using handleEvent on them instead of a function to the handler.
except for these subtle things, I don't think it exists any difference.
For more information see
https://javascript.info/introduction-browser-events#object-handlers-handleevent
I have a Javascript module the following Javascript:
EntryController = function$entry(args) {
MainView();
$('#target').click(function() {
alert('Handler called!');
});
}
MainView() has a callback that creates the #target button. Because of the callback the code will pick up and run through the rest of the code $('#target') ... before #target is created. If this is the case the event is never hooked up to the #target. If I put a breakpoint at $('#target') that'll give the callback enough time to return and build the #target, when I press play everything works as expected.
What's the best way to deal with this? I would like all events to take place in the controller so it can choose which view to send it to.
I was thinking about placing the entire $('#target').click ... inside MainView() and instead of alert('Handler called!'); I'd put a references to EntryController.TargetEventRaise(), but that started to look a bit like steady code. What's the best way to approach this?
You're looking for jQuery's live event handlers, which will handle an event on every element that matches the selector, no matter when the element was created.
For example:
$('#target').live('click', function() {
alert('Handler called!');
});
Alternatively, you could make the MainView function itself take a callback, and add the handler in the callback. You could then call the callback in MainView inside of its callback.