How to make a Javascript event handler to execute first? - javascript

I have a page which uses jQuery & parsley plugin for form validation and submission. Below is the event handler for the form,
$('#formid').parsley().on('form:submit', function(event) {
//handle form submit
});
I have another pure JavaScript listener function to be executed on submit of the form. Below is the code snippet,
document.getElementById("formid").addEventListener("submit",function(e){
//Some code to be executed after form submit
});
I have a requirement not to use jQuery for the above function.
Now the problem is, parsley is stopping flow of events down the line by using event.stopImmediatePropagation();
Because of this, the second event handler is not getting executed. Is there a way I could make my pure javascript handler to execute first? I came across this jQuery solution to bindUp an event handler. But I need pure javascript solution. Any help is greatly appreciated.
Update:
Here is JSFiddle for my problem.

The only way is to ensure that the addEventListener handler is added before the jQuery handler. jQuery will use addEventListener to add its handler for the event (at which point it will use that single handler for all handlers for that event on that element), and since handlers added with addEventListener are processed in the order they were added, your non-jQuery handler will be executed first by the browser.
Example:
// The first addEventListener handler -- does get called
document.getElementById("the-button").addEventListener("click", function () {
console.log("first addEventListener handler called");
}, false);
// The jQuery handler that stops immediate propagation
$("#the-button").on("click", function (e) {
console.log("jQuery handler called");
e.stopImmediatePropagation();
});
// The second addEventListener handler -- doesn't get called
document.getElementById("the-button").addEventListener("click", function () {
console.log("this message won't be output");
}, false);
<input type="button" id="the-button" value="Click Me">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

yes, you can do that. use Boolean true as third parameter to function addEventListener like below. it's binding the handler in capturing phase of the event. for more about capturing and bubbling phase of event see
document.getElementById("formid").addEventListener("submit",function(e){
//Some code to be executed after form submit
}, true);

hope this will help
First way
I don't know if this is going to work, try to refresh your propagation event :
var refEvent = event.originalEvent;
refEvent.cancelBubble = false;
refEvent.defaultPrevented = false;
refEvent.returnValue = true;
refEvent.timeStamp = (new Date()).getTime();
if (event.target.dispatchEvent){
event.target.dispatchEvent(refEvent);
} else if (event.target.fireEvent) {
event.target.fireEvent(refEvent);
}
then you can stop the propagation again after your handler executed by adding event.stopPropagation(); again to your handler this time
Second way
//Listener
var stoped = false;
if(stoped){
event.stopPropagation();
}
//handler
var stoped = true
source : How to undo event.stopPropagation in jQuery?

Related

Override jQuery custom event

I've got the following piece of code that will 'spread' an event to all my js modules. This is intended to be triggered when trying to move away from the current page. The issue is that I don't this to be triggered when the form is submitted (submit/cancel/save). Is there a way to check that?
main.js:
...
$(document).ready(function(){
$(window).on('beforeunload', function(){
var e = $.Event('webapp:page:closing');
$(window).trigger(e);
if (e.isDefaultPrevented()){
return e.message || 'You have unsaved stuff!';
}
});
}
...
Before submit/save/cancel, you can call below code which will remove the handler from all listeners
$(window).off('webapp:page:closing');
On form submit unbind the event:
$("#frm").submit(function(e) {
$(window).off('beforeunload');
});
From MDN: The .off() method removes event handlers that were attached with .on()
The only way that comes to mind is: In the page with the form, when it handles the webapp:page:closing event, it should not prevent the default if it has submitted a form (which it can track via a variable in the page).

JS - Attaching an event listener with return

I routinely use the following JavaScript function to attach events to elements in the DOM.
function addEventHandler(elem,eventType,handler){
if (elem.addEventListener){
elem.addEventListener (eventType,handler,false);
}
else if (elem.attachEvent){
elem.attachEvent ('on'+eventType,handler);
}
}
I would like to use it in the following context to attach some AJAX to a form element onsubmit, and then return false so the form is not actually submitted..
var elemnt = document.getElementById('myForm');
addEventHandler(elemnt, 'submit', function(){
// Do stuff
return false;
});
In the past I would attach a event handler like so: onsubmit="return myfunction();" but I cannot figure out how to get that return in there when attaching event handlers so my function can stop the form from being submitted with JavaScript.
How is this done?
Try:
var element = document.getElementById('myForm');
if (element.addEventListener) {
element.addEventListener('submit', myEventHandler);
}
else {
element.attachEvent('onclick', myEventHandler);
}
function myEventHandler(event){
event.preventDefault();
// Do stuff
}
Update
event.preventDefault() prevents the normal processing of the event after the method in which it is invoked.
It won't prevent the other event listeners to be executed (use event.stopImmediatePropagation() to do that), but it will cancel the default effect of the event. So in this case it should prevent the form to be submitted.
Update 2
The JavaScript engine will invoke the event listener (your function) and pass it an event object describing the event: its type, the object that is the target of the event...
A detailed explanation about event listeners is available here.

jQuery .one() with same function for different events on different elements

I have an introduction on my page which shall disappear when a key is pressed or a certain elements is clicked on. I'll use the same function for both events but as the page is heavily modified the event shall fire only once regardless which way it was triggered.
My function:
function start() {
$('.intro').remove();
$('.something-else').show();
}
How I bind the events:
$('body').keypress(start);
$('.intro').click(start);
If the events were the same I could say
$('body, .intro').one('click', start);
If both events were to happen to the same element I could say:
$('.intro').one('click keypress', start);
How to combine both things: having different elements and different events and the function must only be called once?
The simplest solution would be to store whether your function has been called or not.
var started = false;
function start() {
if(started) return;
$('.intro').remove();
$('.something-else').show();
started = true;
}
Then your function can only be called once, every other call will be ignored.
I don't think this solution is a clean as an explicit approach, but is done using a combination of .one() and .trigger(). Because you call $(".intro").remove() on one of the bound items the event handler is implicitly unbound. Sample Fiddle
Excluding the html seen in fiddle, this is the code.
// Your event handler
function start() {
$("#intro").remove();
$("#main").show();
console.log("start handler called");
}
// Handle the keypress event
$("body").one( "keypress", start );
// Allow user to click through the intro, but trigger the keypress handler on the body which is a one-time event handler)
$("#intro").one( "click", function () { $("body").trigger( "keypress" ); });
Use two lines of code and be done ;)
$('body').one('keypress', start);
$('.intro').one('click', start);
Edit:
You should manually unbind the other callback, lest it runs later, unexpectedly.

preventDefault() doesn't prevent the action

When I use event.preventDefault() on a link it works, however when I use it on a button doesn't!
DEMO
My code:
<a id="link" href="http://www.google.com">link</a>
<button id="button" onclick="alert('an alert')">button</button>​
$('#link').click(function(event){
event.preventDefault();
});
$('#button').click(function(event){
event.preventDefault();
});
​
Link action is cancelled, but when I click on the button, still executes the onClick action.
Any help? what I want to do is to prevent the button onClick action without changing the button html (I know how to do
$('#button').removeAttr('onclick');
You want event.stopImmediatePropagation(); if there are multiple event handlers on an element and you want to prevent the others to execute. preventDefault() just blocks the default action (such as submitting a form or navigating to another URL) while stopImmediatePropagation() prevents the event from bubbling up the DOM tree and prevents any other event handlers on the same element from being executed.
Here are some useful links explaining the various methods:
http://api.jquery.com/event.preventDefault/
http://api.jquery.com/event.stopPropagation/
http://api.jquery.com/event.stopImmediatePropagation/
However, since it still doesn't work it means that the onclick="" handler executes before the attached event handler. There's nothing you can do since when your code runs the onclick code has already been executed.
The easiest solution is completely removing that handler:
$('#button').removeAttr('onclick');
Even adding an event listener via plain javascript (addEventListener()) with useCapture=true doesn't help - apparently inline events trigger even before the event starts descending the DOM tree.
If you just do not want to remove the handler because you need it, simply convert it to a properly attached event:
var onclickFunc = new Function($('#button').attr('onclick'));
$('#button').click(function(event){
if(confirm('prevent onclick event?')) {
event.stopImmediatePropagation();
}
}).click(onclickFunc).removeAttr('onclick');
you need stopImmediatePropagation not preventDefault. preventDefault prevents default browser behavior, not method bubbling.
http://api.jquery.com/event.stopImmediatePropagation/
http://api.jquery.com/event.preventDefault/
The preventDefault function does not stop event handlers from being triggered, but rather stops the default action taking place. For links, it stops the navigation, for buttons, it stops the form from being submitted, etc.
What you are looking for is stopImmediatePropagation.
you can try this:
$('#button').show(function() {
var clickEvent = new Function($(this).attr('click')); // store it for future use
this.onclick = undefined;
});
DEMO
It have helped me
function goToAccessoriesPage(targert) {
targert.onclick.arguments[0].preventDefault();
...
}

Event managment: Replace click event

I have a button with a click event (from a 3. party library) which submits a form. I like to remove the click event, add my own function and call the original event after a validation.
I thought i just add an event.stopImmediatePropagation(); but that did not work. Maybe because of the order the events where added(?).
Is the another way to manage the event execution?
Or how can I get the old event to do something like this:
originalClickEvent = $('#button').doSomeMagicAndGetTheEvent('click');
$('#button').unbind();
$('#button').bind('click', function (event) {
if (valid()) originalClickEvent();
});
Look here Remove all JavaScript event listeners of an element and its children?
After you remove the event listeners you can attach your custom event.
If I've understood you correctly this is the effect you're searching for: http://jsfiddle.net/ftGHq/
In case the click event is just bound to one function you could overwrite that function:
var oldFunction = theOldFunction;
function myFunction(control) {
oldFunction(control);
}
$('#button').unbind();
$('#button').click(myFunction);

Categories