Order of jQuery On Events and Triggers - javascript

See the following:
$('body').on('whyhellothere', function(){
console.log('done...');
});
$('body').triggerHandler('whyhellothere');
This snippet returns:
done...
While if we reverse the order:
$('body').triggerHandler('whyhellothere');
$('body').on('whyhellothere', function(){
console.log('done...');
});
This snippet returns nothing. Why is this the case?

If you shout in the forest, and then I come along, I won't hear anything, would I?
You're registering the event handler after the event was triggered. A registered handler can only listen to events that are triggered after they start listening.
It's simple physics :P

Javascript gets processed top down. It doesn't recognize your on call as some top-level definition that should be processed before something else. So you're calling one function that triggers a handler, that function call looks for all currently registered handlers for that event, of which there are none, and then calls them all (of which there are none). Then you add a new handler to that event listener. And any calls thereafter will iterate the list of handlers (now 1) and call them.

Related

need help understanding this code

this code in book jQuery in action page 131
i don't understand
.trigger('adjustName');
what is adjustName
and Simple explanation for trigger()
thanks :)
$('#addFilterButton').click( function() {
var filterItem = $('<div>')
.addClass('filterItem')
.appendTo('#filterPane')
.data('suffix','.' + (filterCount++));
$('div.template.filterChooser')
.children().clone().appendTo(filterItem)
.trigger('adjustName');
});
It is a string, the name of a custom event you defined.
E.g. it would trigger the event handler bound by:
el.bind('adjustName', function(){...});
For more information I suggest to have a look at the documentation:
Any event handlers attached with .bind() or one of its shortcut methods are triggered when the corresponding event occurs. They can be fired manually, however, with the .trigger() method. A call to .trigger() executes the handlers in the same order they would be if the event were triggered naturally by the user.
Without knowing the context of the code, I would say that calling .trigger() here has no effect, as it is called on the cloneed elements and the event handlers are only cloned if true is passed to clone.
Maybe the original jQuery manual could be helpful?
Description: Execute all handlers and
behaviors attached to the matched
elements for the given event type.
It allows you to trigger, or run, an event. For instance if you wanted the code to mimic the clicking of a button, you could write....
$("#myButton").trigger('click');
This would then run exactly as if you had clicked the button yourself.
'adjustName' is a custom event. So the trigger function is running that custom event. The custom event is assigned using the jQuery bind function.
$("#someElement").bind('adjustName', function() {/* Some Code */});
You might create a customer event for clarity. Perhaps your application opens a document, so you might want an event called 'openDocument' and 'closeDocument' assigned to the element containing the document.

jQuery: Intercept original DOM ready event?

Would it be possible to somehow intercept the DOM ready event so that anything normally triggered within, say, $(document).ready(function() { ... } would not be executed? And then later manually trigger the event so that the code was executed?
In my case, I have a large amount of existing code that already relies on $(document).ready(function() { ... } and my hope is that I would not have to do a search/replace to have all of it rely on a custom manually triggered event.
jQuery.trigger() is made for such need
Any event handlers attached with
.bind() or one of its shortcut methods
are triggered when the corresponding
event occurs. They can be fired
manually, however, with the .trigger()
method. A call to .trigger() executes
the handlers in the same order they
would be if the event were triggered
naturally by the user:
If you do not want something to be "normally" triggered, it should not be in $(document).ready(on_ready_func). Everything inside it will load as soon as the DOM is loaded and before the page contents are loaded.
Instead, from on_ready_func cherrypick the things you want to trigger manually into another function say manual_func, and call that function at event of your choice.
Note that, ready function cannot be triggered using trigger, so you cannot fire the func again, unless you have it as a separate function.
Split-up is your best option.
var manual_func = function(){
// Manual loads
}
var on_ready_func = function(){
// only things to be loaded on dom ready
// e.g.
$('button#load_manual_trigger').bind('click', manual_func);
}
$(document).ready(on_ready_func);
Happy Coding.

Two submit event handlers on a form. One must stop the other

I have to event handlers attached to a form. The first one that fires should stop the other event if a condition is not met.
The code below does not work, as both events will be triggered. Can you help me?
Thanks!
//fires first
$("#myform").submit(function(){
if (some validation) {
alert("You need to make the form valid");
return false;
}
});
//fires second
$("#myform").submit(function(){
//ajax stuff
return false;
});
p.s. I have to this as the ajax stuff is in a plugin that is not changeable. I cannot avoid two event handlers
Have a look at event.stopImmediatePropagation():
Keeps the rest of the handlers from being executed and prevents the event from bubbling up the DOM tree.
$("#myform").submit(function(event){
if (some validation) {
event.stopImmediatePropagation();
alert("You need to make the form valid");
return false;
}
});
You might also want to use event.preventDefault().
Update: Just to clarify: You can rely on the order the event handlers are called. From jQuery's bind method:
When an event reaches an element, all handlers bound to that event type for the element are fired. If there are multiple handlers registered, they will always execute in the order in which they were bound. After all handlers have executed, the event continues along the normal event propagation path.
The order might not be defined in W3C's original definition but it works with jQuery. Otherwise, the above named function would be unnecessary anyway ;)
In short, no. If you have two event handlers, then you have two event handlers. That said however, there are ways around it.
First, remember that javascript execution is single-threaded. If you define a global variable, say var haveCalledSubmit=0;, then you can use that to synch your handlers. For example, if you start each handler function with this:
if(haveCalledSubmit == 1)return haveCalledSubmit = 0;
else haveCalledSubmit = 1;
Then only one of the two handlers will be called. You can easily modify it to match some condition, or to deal with more than two functions.
An alternative is to look into event propagation models. This page will give you all the information you need, although Felix has already mentioned an ajax command that may do what you want.

In jQuery, is there any way to only bind a click once?

I have an ajax app that will run functions on every interaction. I'd like to be able to run my setup function each time so all my setup code for that function remains encapsulated. However, binding elements more than once means that the handler will run more than once, which is obviously undesirable. Is there an elegant way in jQuery to call bind on an element more than once without the handler being called more than once?
User jQuery one function like Tom said, but unbind the handler each time before binding again. It helps to have the event handler assigned to a variable than using an anonymous function.
var handler = function(e) { // stuff };
$('#element').unbind('click', handler).one('click', handler);
//elsewhere
$('#element').unbind('click', handler).one('click', handler);
You can also do .unbind('click') to remove all click handlers attached to an element.
You could attach the event to document with the one() function:
$(document).one('click', function(e) {
// initialization here
});
Once run, this event handler is removed again so that it will not run again. However, if you need the initialization to run before the click event of some other element, we will have to think of something else. Using mousedown instead of click might work then, as the mousedown event is fired before the click event.
You can also use .off() if unbind doesn't do the trick. Make sure the selector and event given to .off exactly match the ones initially provided to .on():
$("div.selector").off("click", "a.another_selector");
$("div.selector").on("click", "a.another_selector", function(e){
This is what worked for me in resolving the same ajax reloading problem.
The answer from Chetan Sastry is what you want. Basically just call a $(element).unbind(event); before every event.
So if you have a function like loadAllButtonClicks() that contains all the
$(element).on("click", function (){});
methods for each button on your page, and you run that every time a button is clicked, this will obviously produce more than one event for each button. To solve this just add
$(element).unbind(event);
before every
$(element).on("click", function (){});
and it will unbind all events to that element, then add the one click event.

Intercept javascript event

Here's what I'm trying to do :
I have a page with some links. Most links have a function attached to them on the onclick event.
Now, I want to set a css class to some links and then whenever one of the links is clicked I want to execute a certain function - after it returns , I want the link to execute the onclick functions that were attached to it.
Is there a way to do what I want ? I'm using jQuery if it makes a difference.
Here's an attempt at an example :
$("#link").click(function1);
$("#link").click(function2);
$("#link").click(function(){
firstFunctionToBeCalled(function (){
// ok, now execute function1 and function2
});
}); // somehow this needs to be the first one that is called
function firstFunctionToBeCalled(callback){
// here some user input is expected so function1 and function2 must not get called
callback();
}
All this is because I'm asked to put some confirmation boxes (using boxy) for a lot of buttons and I really don't want to be going through every button.
If I understand you correctly, is this wat you wanted to do..
var originalEvent = page.onclick; //your actual onclick method
page.onclick = handleinLocal; //overrides this with your locaMethod
function handleinLocal()
{ ...your code...
originalEvent ();
// invoke original handler
}
I would use jQuery's unbind to remove any existing events, then bind a function that will orchestrate the events I want in the order I want them.
Both bind and unbind are in the jQuery docs on jquery.com and work like this...
$(".myClass").unbind("click"); // removes all clicks - you can also pass a specific function to unbind
$(".myClass").click(function() {
myFunctionA();
myFunctionB($(this).html()); // example of obtaining something related to the referrer
});
An ugly hack will be to use the mousedown or mouseup events. These will be called before the click event.
If you can add your event handler before the rest of handlers, you could try to use jQuery's stopImmediatePropagation

Categories