I am trying to make a form with some dynamic behavior. Specifically, I have my inputs in divs, and I would like to make it so when the user clicks anywhere in the div, the input is selected. I was using JQuery 1.2.6 and everything worked fine.
However, I upgraded to JQuery 1.3.2 and I am getting some strange behavior. When I click on any of the inputs, I get a delay before it is selected. My Firefox error console gives me several "too much recursion" errors, from within the JQuery library. I tried the page in Internet Explorer 7 and got an error saying "Object doesn't support this property or method".
Am I doing something wrong, or is this a bug in JQuery? Does anyone know a way to fix this behavior, without going back to the old version? I am using Firefox 3.0.7 in case that matters. Here is a simple example I made to illustrate the problem:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>quiz test</title>
<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
</head>
<body>
<div class='question'>Favorite soda?
<div><input type='radio' name='q' value='A' id='a'><label for='a'>Coke</label></div>
<div><input type='radio' name='q' value='B' id='b'><label for='b'>Pepsi</label></div>
</div>
<script type="text/javascript">
$(function() {
$(".question div").click(function() {
$(this).children("input").click();
});
});
</script>
</body></html>
$(function() {
$(".question div").click(function() {
var radio = $(this).children("input")[0];
radio.checked = !radio.checked;
});
});
ya, click event bubbles up… so when you raise $(this).children("input").click(), you are raising $(".question div").click() again, and so on.
Why do you need to do this if you are using <label for=""> already? Clicking on the label should activate the radio control anyway.
[Edit:] Following up on your comment, you can do it this way:
Make the label display as a block element, apply all styles you have used for the div wrapping the field.
.question label { display:block }
and then use this layout. You can get rid if the divs too.
<label><input type="radio">Coke</label>
<label><input type="radio">Pepsi</label>
Only fire click() when the event's target is the div, ie
$(function() {
$(".question div").click(function(event) {
if($(event.target).is('div'))
$(this).children("input").click();
});
});
I had the same problem when I was going to make my div submit it's child input:submit. This will solve the problem:
$(function() {
$(".question div").click(function() {
$(this).children("input").click(function(event){
event.stopPropagation();
});
$(this).children("input").trigger("click");
});});
The problem (as grilix said) is the event "bubbling up" the DOM, so, there's an easy solution to that, you just need to cancel that bubble effect.
Bubble refers to (plain english) an event being triggered on ALL the elements that are affected because of it's position within the document. So, in your example, the "click" event is received by (in this order) the BODY, then the parent (.question) DIV, then the other DIV and finally by the INPUT.
To do that bubble cancel, you can go the jQuery way by calling the stopPropagation method within your callback function, like this:
$(function() {
$(".question div").click(function(event) {
$(this).children("input").click();
event.stopPropagation();
});
});
The plain javascript way would require you to use the cancelBubble method, but I guess it is outside the scope of your question.
Greetings,
Manolo
<script type="text/javascript">
$(function() {
$(".question div").click(function() {
$(this).find("input").attr("checked", "checked");
});
});
</script>
PS: It was recursing too much probably because you were stopping the propagation of divs' clicks, not the inputs' clicks.
I dont remember about how to check radios with jQuery, but could be like this:
<script type="text/javascript">
$(function() {
$(".question div").click(function() {
$(this).children("input").checked(true);
// or
$(this).children("input").checked= true;
});
});
</script>
I know this may be not the answer at all, but i am writing it as it happened to me before:
It gave me “too much recursion” error while i was using jquery and prototype in the same project and also this may happen with ajax.net with jquery, so make sure that there is no conflict between libraries if you are using more than one.
Thank you all. I tried grillix's idea of setting the checked attribute, although I had to fix up the syntax a little bit. Here is what I did:
$(this).children("input").attr("checked", true);
It works, but I am still curious as to why my previous way stopped working with JQuery 1.3.2. I know about the changes in event bubbling behavior, but why can't I fix that by calling "event.stopPropagation()" or "return false" within my callback?
Related
Please run this sample in Google Chrome browser.
Stack Snippet
$(function() {
$(":input").select(function() {
$("div").text("Something was selected").show().fadeOut(1000);
alert("Selected");
});
$("button").click(function() {
$(":input").select();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<button>Click To Select</button>
<input type="text" value="Some text">
<div></div>
Here why jQuery select event listener is triggering multiple times? Does anyone know the reason behind this? And is there any workaround solution for this without using timeout?
The $(":input") selector is selecting the button too, so it causes recursion. Either use just $("input"), or $(":input:not(button)").
I noticed when the three events are fired, the first doesn't have originalEvent property, so we definitely can dismiss it, and the second two has very similar (however not identical) timestamp. You can store the last timestamp in some variable and in event listener compare it with the event's timestamp. If the rounded values of these two are the same, you can dismiss this event.
$(function() {
var lastTimeStamp;
$("input").select(function(event) {
if (!event.originalEvent ||
lastTimeStamp === Math.round(event.timeStamp)) return;
lastTimeStamp = Math.round(event.timeStamp);
$("div").text("Something was selected").show().fadeOut(1000);
alert("Selected");
});
$("button").click(function() {
$("input").select();
});
});
See updated JS Fiddle.
It appears the issue is a combination of:
the :input selector gets the input and the button, hence multiple events triggered.
even when using just input as the selector there is some odd event propagation being triggered on related elements which is raising the select event handler multiple times.
To avoid both of the above, use input as the selector and also use preventDefault() in the event handler. stopPropagation() may also be required, depending on your HTML stucture.
$(function() {
$('input').select(function(e) {
// e.stopPropagation(); // optional
e.preventDefault();
$('#message').text("Something was selected").show().fadeOut(1000);
console.log('Selected');
});
$('button').click(function() {
$('input').select();
});
});
Working example
UPDATE: We were all fooled. The select() function needs a prevent default.
Rory McCrossan figured it out. Well done mate.
Incidentally, I'm not sure what the benefit of select() actually is! Something like focus() or on('focus',) might make more sense. Not Sure what the context is however. The below still follows:
Why waste time using generalised tag/type selectors which may change? Use an ID, and pick out only the one you want.
If you want to detect multiple, use a class. If you want to use multiple, but figure out which one you clicked, use a class and an ID. Bind with the class, and identify using $this.attr('id').
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<button>Click To Select</button>
<input type="text" value="Some text" id="pick-me">
<div></div>
$(function() {
$("#pick-me").select(function(event) {
event.preventDefault();
$("div").text("Something was selected").show().fadeOut(1000);
alert("Selected");
});
$("button").click(function() {
$("#pick-me").select();
});
});
alrighty Ive got what I hope is a rather easy question today for people knowledgeable in jquery. I have an toggle that activates on clicking a specific element, in this case I have targeted my logo image with an id of #logobutton. it works wonderfully however theres a problem, the animation also activates whenever I click on any and all other links on the page and even some random div boxed (like my nav bg). please note im very new to this javaScript jazz so I may be missing something you would consider quite obvious. thanks for the help!
here is the fiddle with all relevant code http://jsfiddle.net/tRf36/1/
jquery:
!--jquery script, must be above all jquery elements-->
<script type="text/javascript" src="jquery-1.11.0.min.js"></script>
<!--script for bg toggle-->
<script type="text/javascript">
$( document ).ready(function() {
$("#logobutton").click(function() {
$(".galbox").toggleClass("galbox-change");
});
});
</script>
<!--bg fade hide on load-->
<script>
$(document).ready(function(){
$("#gallerybox").fadeTo(3000, 0.00, function() {
$("#gallerybox").fadeTo(1000, 1.00);
});
});
</script>
hopefully someone can see if I have something targeted incorrectly or whatever is causing the issue of my generic rather than specific selection of clickable area to activate this bg animation.
My previous answer was completely off base, sorry for that. Looking at the jsfiddle that you posted it appears that you have the logo button like this <button ... /> the browser is then ignoring the /> and just wrapping everything in a button. So that means that both the gallery box and the nav bar are surrounded by the button that is activating the animation. Changing the button to be like this should fix it:
<button type="button" class="logo" id="logobutton" value=""></button>
close <button> tag properly using </button>
All elements below button are treated as children if you do not close properly.
Two aspects conspire to cause the effect:
You have nested your nav bar divs inside the #logobutton button.
Event bubbling causes events triggered on an embedded element to eventually reach the #logobutton button, being processed by the registered event handler.
A solution is to check for the triggering element of the click event:
$("#logobutton").click(function (eve) {
if ($(eve.target).attr("id") === "logobutton") {
$(".galbox").toggleClass("galbox-change");
}
});
You can test this modification with this fiddle.
You can learn more about event bubbling in particular and event processing in browsers following these links:
quirksmode (ppk)
MDN
I have animated datatables which slide in from the left when their hyperlink is clicked. And when the user is done reading the contents of the visible datatable, I applied the following code to allow the user to click anywhere else to park the table away and proceed with viewing. I used jQuery code for attaching the click event...
<script type="text/javascript" charset="utf-8">
$(document).ready( function () {$('.dtable').dataTable( {"sDom": 'rt',"sScrollY":"200px", "bPaginate":false, "bFilter":false} );**$('body').click(function() {parkDataTables();});})
</script>
Unfortunately, clicking on the datatable itself parks it. And I don't want that behavior. Maybe someone has an idea on how to block this click event from firing on the surface of the datatable...
Many thanks
Dennis
Instead of using body as the selector you could use
$('body').children().not('.dtable')
So you would get
<script type="text/javascript" charset="utf-8">
$(document).ready(
function () {
$('.dtable').dataTable( {"sDom": 'rt',"sScrollY":"200px", "bPaginate":false, "bFilter":false} );
$('body').children().not('.dtable').click(function() {
parkDataTables();
});})
</script>
You should do it with
$('.dtable').click(function(){return false;});
The problem is that when you click on the table, the event goes into the table first and then it propagates to the parents (and finally to the body, when the parkDataTables is catched).
You could also use stopPropagation instead ( http://api.jquery.com/event.stopPropagation/ ), because with the return false you also stop the default click behavior on the table.
$('.dtable').click(function(event){
event.stopPropagation();
});
Maybe you could check this page to see this last difference: http://fuelyourcoding.com/jquery-events-stop-misusing-return-false/
Jquery propagates the function up through every parent. In order to stop the propagation, you must "return false;".
In your case, you want to try:
> $('body').click(function() { if $(this).hasClass('dtable'){return
> false;}) if $(this).hasClass('body'){park}
And give your body a class of 'body' to make it selectable.
i am a bit new to using jquery, the following should display a button, and when someone clicks the button, the font size of that button should change.
Unfortunately, the button does not change its font size, for reasons i am not sure of.
Edit:
this example is the same one as before with adjustments, it works but it will only change font, once the mouse has left the button's area or if the button has be double clicked.
The font should change on only 1 click.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
$(".button0").click(function() {
$('.button0').css('font-size', '43px');
});
});
</script>
<style type="text/css">
.button0{
position:fixed;
left:48px;
top:55px;
font-family:Arial;
font-size:8px;
font-weight:normal;
}
</style>
<body>
<div name="button0"><input class="button0" type="button" style="width: 148px;height: 72px;" value="Button"/></div>
</body>
</html>
By the time .click is called, the DOM hasn't fully loaded. You should wrap it in a DOM ready function.
$(function() {
$(".button0").click(function() {
$('.button0').css('font-size', '43px');
});
});
Also noted its not a div.
You have to make sure the document is ready—as in, all elements have loaded—before making modifications.
Wrap everything in this function:
$(document).ready(function(){
// your code here
});
Besides that, your selector is looking for a div element with a class of button0 when you're trying to modify an input element. Modify your selector to say input.button0.
Also, jQuery has a $(this) selector which selects the current element. In your case it will select the clicked input.
And finally, since you're using jQuery 1.7.1, I'll introduce you to on(). It's generally recommended to delegate events using this function. Instead of $(div).click(), use this:
$(document).on("click", "input.button0", function(){
$(this).css("font-size", "43px");
});
More about on() here.
Why are you using div.button0. The element isn't a div. try just .button0.
That is because the javascript is executed as soon as it is encountered; so it is executed before the button is rendered.
Change the order and it'll work.
<input class="button0" type="button" style="width: 148px;height: 72px;" value="Button"/>
<script type="text/javascript">
$(".button0").click(function() {
$('.button0').css('font-size', '43px');
});
</script>
jQuery also includes a domready event for this, which means the javascript will be parsed before the button but will only be executed when the button is there. This way, you can still put the javascript in the head, if you'd really want to. To do this, just wrap the existing code in
$(function() {
/*code*/
});
Need to properly fire off the event for attaching .click()
<script type="text/javascript">
$(document).ready(function() {
$(".button0").click(function() {
$(this).css('font-size', '43px');
});
});
</script>
Note the class name .button0 as it is NOT in a DIV as you previously used.
use it like this
$(document).ready(function(){
$("div.button0").click(function() {
$(this).css('font-size', '43px');
});
});
I used jQuery to set hover callbacks for elements on my page. I'm now writing a module which needs to temporarily set new hover behaviour for some elements. The new module has no access to the original code for the hover functions.
I want to store the old hover functions before I set new ones so I can restore them when finished with the temporary hover behaviour.
I think these can be stored using the jQuery.data() function:
//save old hover behavior (somehow)
$('#foo').data('oldhoverin',???)
$('#foo').data('oldhoverout',???);
//set new hover behavior
$('#foo').hover(newhoverin,newhoverout);
Do stuff with new hover behaviour...
//restore old hover behaviour
$('#foo').hover($('#foo').data('oldhoverin'),$('#foo').data('oldhoverout'));
But how do I get the currently registered hover functions from jQuery?
Shadow2531, I am trying to do this without modifying the code which originally registered the callbacks. Your suggestion would work fine otherwise. Thanks for the suggestion, and for helping clarify what I'm searching for. Maybe I have to go into the source of jquery and figure out how these callbacks are stored internally. Maybe I should change the question to "Is it possible to do this without modifying jquery?"
Calling an event bind method (such as hover) does not delete old event handlers, only adds your new events, so your idea of 'restoring' the old event functions wouldn't work, as it wouldn't delete your events.
You can add your own events, and then remove them without affecting any other events then use Event namespacing: http://docs.jquery.com/Events_(Guide)#Namespacing_events
Not sure if this will work, but you can try this:
function setHover(obj, mouseenter, mouseleave) {
obj.data("_mouseenter", mouseenter);
obj.data("_mouseleave", mouseleave);
obj.hover(obj.data("_mouseenter"), obj.data("_mouseleave"));
}
function removeHover(obj) {
obj.unbind("mouseenter", obj.data("_mouseenter"));
obj.unbind("mouseleave", obj.data("_mouseleave"));
obj.data("_mouseenter", undefined);
obj.data("_mouseleave", undefined);
}
$(document).ready(function() {
var test = $("#test");
setHover(test, function(e) {
alert("original " + e.type);
}, function(e) {
alert("original " + e.type);
});
var saved_mouseenter = test.data("_mouseenter");
var saved_mouseleave = test.data("_mouseleave");
removeHover(test);
setHover(test, function() {
alert("zip");
}, function() {
alert('zam');
});
removeHover(test);
setHover(test, saved_mouseenter, saved_mouseleave);
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Jquery - Get, change and restore hover handlers</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<p><a id="test" href="">test</a></p>
</body>
</html>
If not, maybe it'll give you some ideas.
I'm not sure if this is what you mean, but you can bind custom events and then trigger them.
http://docs.jquery.com/Events/bind
So add your hover event, script the functionality you need for that hover, then trigger your custom event.
Maybe it would be easier to just hide the old element and create a clone with your event handlers attached? Then just swap back in the old element when you're done..