Using JavaScript / jQuery event handler in Firefox - javascript

I have a jQuery function that submits a form via menu navigation functions:
$(function () {
$('#sidebarmenu1 a').on('click', function () {
var url = $(this).attr('href');
$('#myform').attr('action', url);
$("#myform").submit();
if (event.preventDefault) { event.preventDefault(); } else { event.returnValue = false; }
})
});
This section:
if (event.preventDefault)
{ event.preventDefault(); }
else
{ event.returnValue = false; }
Prevents the default action of the sidebar button (I think - still new to this) i.e. to simply navigate to a page.
It is written in this way to keep IE happy, because preventDefault isn't defined for IE (might be using incorrect terminology there, but IE doesn't like preventDefault.)
However now this throws up an error in Firefox, because (as I read on other Stack questions) event is not globally defined for Firefox! I get the following error:
ReferenceError: event is not defined
Now according to this Stack question:
event is not defined in FireFox, but ok in Chrome and IE
In IE and Chrome, event is resolving to window.event. Firefox doesn't have this property and instead provides an event to an event handler function by passing it as a parameter. jQuery abstracts this difference for you by providing an event object parameter in all browsers.
But I thought I was using jQuery here and am still getting the issue.
Sorry if I'm making basic mistakes, self teaching myself js and jQ. Any help much appreciated.

This should do..
$(function() {
$('#sidebarmenu1 a').on('click', function(e) {
var evt = e || window.event;
var url = $(this).attr('href');
$('#myform').attr('action', url);
$("#myform").submit();
evt.preventDefault();
})
});​

If you use the event object jQuery passes to the event handler you wont have problems
$('#sidebarmenu1 a').on('click', function (event) {
var url = $(this).attr('href');
$('#myform').attr('action', url);
$("#myform").submit();
event.preventDefault();
})

If I had a couple of more points I would up-vote the second answer (passing in the jQuery 'event' argument).
I had unknowingly relied on the global event defined by browsers other than Firefox. I went back through my code and ensured I was always specifying the event parameter on all click events.
E.g.
$('#situationTextInput')
.val('')
.fadeTo(1000, 1.0)
.focus()
.off('keydown')
.on('keydown', function (event) {
VsUtils.handleSpanishTextKeydown(event);
});
I've also gotten into the habit of calling .off prior to .on as most of my code is using single pages, reusing content. Without the .off I was inadvertently stacking up events (even if they were the same callback) in subsequent steps of the dialog.
A side effect of changing my code to pass on 'event' directly to the handler was the binding to 'this.' changed. I chose to refactor the code to change 'this.' references to 'event.currentTarget.'

Related

How can I return a href link to it's default behavior after using e.preventDefault();?

I updated my code and rephrased my question:
I am trying to create the following condition. When a link with an empty href attribute (for example href="") is clicked, a modal is launched and the default behavior of that link is prevented..
But when the href attribute contains a value (href="www.something.com") I would like for the link to work as it normally does using its default behavior.
For some reason my code isn't working. Any help is appreciated.
// Semicolon (;) to ensure closing of earlier scripting
// Encapsulation
// $ is assigned to jQuery
;(function($) {
// DOM Ready
$(function() {
// Binding a click event
// From jQuery v.1.7.0 use .on() instead of .bind()
$('.launch').bind('click', function(e) {
var attrId = $(this).attr('attrId');
if( $('.launch').attr('href') == '') {
// Prevents the default action to be triggered.
e.preventDefault();
// Triggering bPopup when click event is fired
$('div[attrId="' + attrId+'"]').bPopup({
//position: ['auto', 'auto'], //x, y
appendTo: 'body'
});
} else {
$(this).removeAttribute('attrId');
return true;
}
});
});
})(jQuery);
Your jQuery is... very wrong. $('href').attr('') is getting the empty attribute from an element <href>... Did you mean:
if( $(this).attr('href') == '')
A few things: event is undefined, as your event object is simply called e. Secondly, e.stopPropagation(); will not do what you want. stopPropagation simply prevents parent events from firing (eg: clicking a <td> will also fire click on the containing <tr> unless stopped).
Try just replacing your else statement with
return true;
Also your jQuery is incorrect (as stated in the other answer here).
This answer may help as well:
How to trigger an event after using event.preventDefault()
Good luck!

event.preventDefault() in a href="#" doesn't prevent jumping to top of page in IE and Firefox

HTML:
<a href="#" class="button" onclick="sendDetails(\'Edu\')">
JS:
function sendDetails(type) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
names = $("#names" + type).val();
Input = encodeURIComponent($("#Input" + type).val());
....
The link jumps to top of page. I tried to use event.preventDefault() to stop jumping to top of page. However, it works only in Chrome and not in IE and Firefox. How can I solve it?
instead of "#" you can use javascript:; so there is no jumping, make sure to return false to disable the link-behavior
link
You can't only use the window.event to control an event. Try standardizing it like:
function sendDetails(e, type) {
var evt = window.event || e;
if (evt.preventDefault) {
evt.preventDefault();
} else {
evt.returnValue = false;
}
// ...
}
And your HTML would have to be:
ASDF
One other non-jQuery solution is to just modify your HTML to be:
ASDF
in which case you wouldn't have to use anything dealing with event in your sendDetails function. The return false; will prevent the default behavior automatically. But note - if any exceptions occur in your sendDetails function, the return false; won't execute and will allow the default behavior. That's why I like using preventDefault - you can call it immediately in the function to immediately stop the behavior, then do what you need.
At the same time, if you're using jQuery, try binding the click event like this:
$(document).ready(function () {
$(".button").on("click", function (e) {
e.preventDefault();
// Your sendDetails code (without the "event" stuff)
// OR call sendDetails (and remove the "event" stuff in the sendDetails function)
});
});
in which case your HTML would be:
ASDF
Although it would be a lot easier to target the specific elements that this applies to, instead of using the .button selector I provided. I'm sure the "button" class applies to more than just these targeted <a>, but maybe I'm wrong :)
Using jQuery is nice in this situation because it already standardizes the event object in a way that you can just use that e variable I included in the click callback. I'm sure it does a little more than just window.event || e, so I'd prefer/suggest using jQuery for handling events.
You are already using jQuery, just do it the jQuery way. jQuery wraps the event object and provides a normalized event object so you can just use the standard preventDefault, you don't need to fork depending on what the browser supports.
<button class="senddetail" data-type="edu">Education</button>
<button class="senddetail" data-type="com">Commercial</button>
<!-- why not just use a button instead of styling a link to look
like a button? If it does need to be a link for some reason
just change this back to an anchor tag, but keep the data
attributes and change the class to "button senddetail" -->
<script>
function sendDetails(type) {
// Assuming names and input are not globals you need to declare
// them or they will become implicit globals which can cause
// all sorts of strange errors if other code uses them too
var names, input;
names = $("#names" + type).val();
// you should only use capitalized variables for
// Constructor functions, it's a convention in JS
input = encodeURIComponent($("#Input" + type).val());
//....
}
// just calling $ with a function inside of the invocation
// is the same as using $(document).ready
$(function () {
// instead of using onClick, use jQuery to attach the
// click event in a less intrusive way
$('.senddetail').on('click', function (event) {
// no matter what browser this runs in jQuery will
// provide us a standard .preventDefault to use
event.preventDefault();
// jQuery sets 'this' to the DOM element that the event fired on,
// wrapping it in another jQuery object will allow us to use the
// .data method to grab the HMLM5 data attribute
var type = $(this).data('type');
sendDetails(type);
});
});
</script>

jQuery click event triggered multiple times off one click

I am having trouble with multiple clicks being registered in jQuery when only one element has been clicked. I have read some other threads on Stack Overflow to try and work it out but I reckon it is the code I have written. The HTML code is not valid, but that is caused by some HTML 5 and the use of YouTube embed code. Nothing that affects the click.
The jQuery, triggered on document.ready
function setupHorzNav(portalWidth) {
$('.next, .prev').each(function() {
$(this).click(function(e) {
var target = $(this).attr('href');
initiateScroll(target);
console.log("click!");
e.stopPropagation();
e.preventDefault();
return false;
});
});
function initiateScroll(target) {
var position = $(target).offset();
$('html, body').animate({
scrollLeft: position.left
}, 500);
}
}
Example HTML
<nav class="prev-next">
Prev
Next
</nav>
In Firefox one click can log a "Click!" 16 times! Chrome only sees one, but both browsers have shown problems with the above code.
Have I written the code wrongly or is there a bug?
-- Some extra info ------------------------------------------
setupHorzNav is called by another function in my code. I have tested this and have confirmed it is only called once on initial load.
if ( portalWidth >= 1248 ) {
wrapperWidth = newWidth * 4;
setupHorzNav(newWidth);
}
else
{
wrapperWidth = '100%';
}
There are mutiple instances of nav 'prev-next'. All target different anchors. All are within the same html page.
<nav class="prev-next">
Prev
</nav>
Try unbinding the click event like this
$(this).unbind('click').click(function (e) {
});
You don't need .each() for binding event handlers. Try this instead:
$('.next, .prev').click(function(e){
var target = $(this).attr('href');
initiateScroll(target);
console.log("click!");
e.stopPropagation();
e.preventDefault();
return false;
});
EDIT:
I think it is the way you are attaching the event handler from within the setupHorzNav function that is causing it. Change it to attach it only once from say, $(document).ready() or something.
I have managed to get the situation of multiple event handlers by attaching the event handlers from a function that gets called from event handler. The effect is that the number of click event handlers keeps increasing geometrically with each click.
This is the code: (and the jsfiddle demo)
function setupNav() {
$('.next, .prev').each(function () {
$(this).click(function (e) {
setupNav();
var target = $(this).attr('href');
console.log("click!");
e.stopPropagation();
e.preventDefault();
return false;
});
});
}
setupNav();
See how calling the setupNav() function from the click event handler adds multiple eventhandlers (and the click log message) on successive clicks
Since it is not clear from your question whether you are calling the binding function multiple times, a quick and dirty fix would be:
$('.next, .prev').unbind('click').click(function() {
...
});
What you are doing here is unbinding any previously bound event handlers for click and binding afresh.
Are there no other click bindings elsewhere?
Are you loading the page with ajax?
You could also try this:
$('.next, .prev').click(function (e) {
var target = $(this).attr('href');
initiateScroll(target);
console.log("click!");
e.stopPropagation();
e.preventDefault();
return false;
});

Is there a [universal] way to invoke a default action after calling event.preventDefault()?

This question is for the purposes of developing jQuery plugins and other self-contained JavaScript snippets that don't require modifying other script files for compatibility.
We all know that event.preventDefault() will prevent the default event so we can run a custom function. But what if we want to simply delay the default event before invoking it? I've seen various, case-specific ninja tricks and workarounds to re-invoke the default action, but like I said, my interest is in a universal way to re-trigger the default, and not deal with default triggers on a case-by-case basis.
$(submitButton).click(function (e) {
e.preventDefault();
// Do custom code here.
e.invokeDefault(); // Imaginary... :(
});
Even for something as simple as form submission, there seems to be no universal answer. The $(selector).closest("form").submit() workaround assumes that the default action is a standard form submission, and not something wacky like a __doPostBack() function in ASP.NET. To the end of invoking ASP.NET callbacks, this is the closest I've come to a universal, set-it-and-forget-it solution:
$(submitButton).click(function (e) {
e.preventDefault();
// Do custom code here.
var javascriptCommand = e.currentTarget.attributes.href.nodeValue;
evalLinkJs(javascriptCommand);
});
function evalLinkJs(link) {
// Eat it, Crockford. :)
eval(link.replace(/^javascript:/g, ""));
}
I suppose I could start writing special cases to handle normal links with a window.location redirect, but then we're opening a whole new can of worms--piling on more and more cases for default event invocation creates more problems than solutions.
So how about it? Who has the magic bullet that I've been searching for?
Don't call preventDefault() in the first place. Then the default action will happen after your event handler.
Take a look at this one:
You could try
if(!event.mySecretVariableName) {
event.preventDefault();
} else {
return; // do nothing, let the event go
}
// your handling code goes here
event.originalEvent.mySecretVariableName = "i handled it";
if (document.createEvent) {
this.dispatchEvent(event.originalEvent);
} else {
this.fireEvent(event.originalEvent.eventType, event.originalEvent);
}
Using this answer: How to trigger event in JavaScript? and the jQuery event reference: http://api.jquery.com/category/events/event-object/
Tag the event object you receive so if you receive it again you don't loop.
This should work. I've only tested in firefox though.
<html>
<head>
<script>
window.addEventListener("click",handleClick,false);
function handleClick(e){
if (e.useDefault != true){
alert("we're preventing");
e.preventDefault();
alert(e.screenX);
//Firing the regular action
var evt = document.createEvent("HTMLEvents");
evt.initEvent(e.type,e.bubbles,e.cancelable);
evt["useDefault"] = true;
//Add other "e" attributes like screenX, pageX, etc...
this.dispatchEvent(evt);
}
else{
alert("we're not preventing");
}
}
</script>
</head>
<body>
</body>
</html>
Of course, you'd have to copy over all the old event variables attributes too. I just didn't code that part, but it should be easy enough.
It's not possible like JamWaffles has already proven. Simple explanation why it's impossible: if you re-trigger the default action your event listener intercept again and you have an infinite loop.
And this
click(function (e) {
e.preventDefault();
// Do custom code here.
e.invokeDefault(); // Imaginary... :(
});
is the same like this (with your imaginary function).
click(function (e) {
// Do custom code here.
});
It seems that you want to manipulate the url of your clicked element. If you do it like this it just works fine. Example.
I needed to disable a button after click and then fire the default event, this is my solution
$(document).on('click', '.disabled-after-submit', function(event) {
event.preventDefault();
$(event.currentTarget).addClass('disabled');
$(event.currentTarget).removeClass('disabled-after-submit');
$(event.currentTarget).click();
$(event.currentTarget).prop('disabled', true);
});

Handling clicks outside an element without jquery

I would like to implement the solution like this
How do I detect a click outside an element?
but I'm using another javascript library with $() function already defined
Any suggestions?
This is easy to accomplish. Would be a shame to load the jQuery library just for one feature.
If the other library you're using handles event binding, you could do the same thing in that library. Since you didn't indicate what that other library is, here's a native solution:
Example: http://jsfiddle.net/patrick_dw/wWkJR/1/
window.onload = function() {
// For clicks inside the element
document.getElementById('myElement').onclick = function(e) {
// Make sure the event doesn't bubble from your element
if (e) { e.stopPropagation(); }
else { window.event.cancelBubble = true; }
// Place the code for this element here
alert('this was a click inside');
};
// For clicks elsewhere on the page
document.onclick = function() {
alert('this was a click outside');
};
};
If the $ conflict is your only hold-up, there are ways around that:
http://docs.jquery.com/Using_jQuery_with_Other_Libraries
I also add here the code that stops event bubbling up. Found on quircksmode.org
function doSomething(e) {
if (!e) var e = window.event
// handle event
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
}

Categories

Resources