I have a problem that happens only on a specific computer(FFX 3.6.13,Windows 7,jQuery 1.4.3).
Sometimes document.ready is fired but when trying to get elements to attach the event handlers,the elements don't exist!
the code goes something like this:
$(function(){
window.initStart = true;
$("#id_of_element").click(function()...);
window.initEnd = $("#id_of_element");
});
the window.initStart/End are there for debugging,sometimes this code runs just fine,but sometimes window.initEnd is just a empty jQuery set(length == 0).
What this means is that document.ready is always fired,but sometimes it is fired before elements are available.
Does anybody had this problem? what could the problem be?
One way that you could try to get around this would be with using .live instead of .click. The following code
$('#idOfDiv').live('click', function() { doStuff(); });
will attach the input function to the click event of everything that is dropped on the page with an id of 'idOfDiv' as soon as it makes it to the page. Whereas .click executes immediately, this should be attached no matter what time the divs make it to the page.
Cheers
There's an article on SitePoint that demonstrates how to sense when certain dom elements are available.
Also I know this is a version specific issue, but if you were on Jquery 1.5 the deferred objects stuff would be useful here.
Related
I use the following jquery in my page.
var j = jQuery.noConflict();
j(document).ready(function(){
console.log(j("#label_19"));
j("#label_19").on("click",function(){
alert("Clicked");
});
});
When document loads, the element (it's a checkbox) appears in the console. But when I click the checkbox, the alert is not thrown. But when I copy the same code (as below)
j("#label_19").on("click",function(){
alert("Clicked");
});
in console panel and press run. Now when I click the checkbox, the alert is thrown. What could be the issue in this case?
Updated:
What I observe in console is:
Object[input#label_19.document_label attribute value = "Check-In"]
The HTML markup is
<input id="label_19" class="document_label" type="checkbox" value="Check-In" name="label[19]">
The only explanation that fits the facts you've presented is that there is code running after your ready callback but before you click the element that replaces the element in question. Some kind of ajax callback or similar.
You'll need to look through your code to find the place where that's happening. Things to look for are any html calls on elements that contain the #label_19 element, or (if there's a mix of jQuery and non-jQuery code) assignments to innerHTML.
You can use event delegation to solve this, which may or may not be the best answer depending on what your code is doing. That looks like this:
var j = jQuery.noConflict();
j(document).ready(function(){
console.log(j("#label_19"));
j(document).on("click", "#label_19", function(){ // This is the changed line
alert("Clicked");
});
});
There, instead of hooking click on the actual element, we're hooking it on document but then asking jQuery to only tell us about clicks that pass through elements matching the selector we give it as they bubble. That way, the fact that something is destroying and recreating the #label_19 element doesn't matter, because we're not hooking a handler on that element. We're hooking the handler on document and checking, when the event occurs, if it passed through something that matches that selector.
But I wouldn't just blindly use event delegation, I'd find out what's really happening with that element.
Without seeing the rest of your code—including HTML and related DOM elements—have you considered using j(window).load() instead of j(document).ready()
var j = jQuery.noConflict();
j(window).load(function(){
console.log(j("#label_19"));
j("#label_19").on("click",function(){
alert("Clicked");
});
});
As explained here:
The window load event executes a bit later when the complete page is fully loaded, including all frames, objects and images. Therefore functions which concern images or other page contents should be placed in the load event for the window or the content tag itself.
I had a similar issue, it got resolved after i wrapped it in a window.load
(function ($) {
$(window).on('load', function () {
//MY click calls inside here
});
})(jQuery);
Hope it helps!
I've come across an issue where jQuery events fire twice after $.load() is called. The event handler is placed in the load() callback function, and this seems to be the only place where events fire twice on the script.
I've tried adding event.stopPropogation() and event.preventDefault(), as these seem to be common suggestions with jQuery events firing more than one. I'm not sure if my code is bubbling improperly or what. Any feedback would be helpful.
Here's an extract of some of the code where you see the behavior.
$("div.questions").load("question_source.php #simplified_a", function(){
...
// Line 1
$("#some_id").change(function(){
cantBeNegative(this);
adjusted_gross_income = $(this).val();
console.log(adjusted_gross_income);
// event.stopPropagation();
// event.preventDefault();
});
You can clearly see the event firing twice with the console.log bit I've got in there. Any advice would be appreciated!
EDIT
OK, I checked through everything on the live page based on some of the suggestions, and there's definitely only one <div id="questions"> in existence when the problem is occurring. So, it doesn't appear to be an HTML problem.
I also checked to see if the event was actually being called twice, and as far as I can tell, the event is only being called once.
Now, I added a .on() event attached to the document which is called on the dynamically created elements, and that only fires once. .on() is not called within the .load() callback. Here's an example used on one of the other input boxes on the page which works without any problems:
$(document).on('change', "#SWA_mothers_income", function(){
console.log("mothers income changes from on()");
});
So, that works properly, but when tested on the same input within the .load() callback function, it fires twice, regardless of how it's called. So, it seems to me that it's almost certainly an issue with .load(). I wouldn't exactly call myself an expert in this, so if someone can figure out the issue, I'd love to know the answer. As it stands, I'm going to rewrite this code using .on().
SECOND EDIT
Adding $("#some_id").unbind('change');
before the 'change(function()) bit did the trick!
add this line
$("#some_id").unbind('change');
before
$("#some_id").change(function(){});
I'm not saying this will solve your problems but you need to pass in the event to reference it.
$("#some_id").change(function(event){
cantBeNegative(this);
adjusted_gross_income = $(this).val();
console.log(adjusted_gross_income);
event.stopPropagation();
event.preventDefault();
});
It's possible that you have two divs with a class of 'questions', so you could be binding the change function twice.
If you update your change function to the below, this will unbind the change event before re-adding it. This will make sure you only have the function bound once;
$("#some_id").unbind('change').change(function(event) {
event.preventDefault();
cantBeNegative(this);
adjusted_gross_income = $(this).val();
console.log(adjusted_gross_income);
});
It seems that this code:
$(function(){
$('.show_hide_login').toggle(
function (){
alert('show');
$("div#fullpage").show();
$("div#loginbox").show();
},
function (){
alert('hide');
$("div#loginbox").hide();
$("div#fullpage").hide();
}
); });
Any idea on why it would be running twice when I click on either link (two, one is a div and one is an anchor)?
How many elements do you have with the .show_hide_login class? I'll guess you have two of those. In which case, $('.show_hide_login') result contains two elements, and toggle() is executed for each of them.
This isn't an answer to your question, but you could clean up your code a bit like so:
$(function() {
$('.show_hide_login').toggle(
function() {
alert('show');
$("#loginbox,#fullpage").show();
}, function() {
alert('hide');
$("#loginbox,#fullpage").hide();
});
});
As to your actual problem, I suspect Nick's guessed the culprit. Check out this demo to see the result of binding the same event twice: http://jsfiddle.net/9jPLv/
In addition to adding an alert prior to the binding of the toggle event, you could add in an unbind() and see if that solves the problem, like so:
$('.show_hide_login').unbind().toggle(
If that solves it, the toggle binding is definitely being run twice, so you'd just have to figure out why.
my answer is just a kind of checkpoint,i had the same issue but for different reason. I did include the script file in base page as well as child page. this resulted in toggle running twice if you have this problem check that the script is added only once.
It might be the same issue i was having.
so if you got an element with a script tag in it - then you move that containing element or wrap it with another tag in jquery - then the ready function in jquery is executed again - thus binding a second toggle function to your element.
as suggested $('.show_hide_login').unbind().toggle( is a workaround that does work, but better to try moving your javascript code to the head or bottom of the page.
I have a number of jQuery scripts that select elements within the area that I run a partial page refresh on.
I am using this css tricks code snippet to refresh that part of the page:
$('#refreshbutton').click(function() {
var url = "http://myUrl.com/indexTest.php?ID=" + Math.random();
setTimeout(function() {
$("#maindisplay").load(url+" #maindisplay>*","");
}, 100);
});
The problem is that the elements within #maindisplay are changed, thus are considered new elements in the dom. Since the scripts that select those elements and attach functions to them run at domready and not during the partial refresh, this poses a problem.
So far I have been unable to find a way to reattach the scripts to the elements within #maindisplay after I partially refresh it.
My question is: What is the optimal way to reattach the scripts to the refreshed area of the page.
Thank you for any advice.
You need to use the live() function to attach your click handler.
You have the following options that I can think of:
Put the attach in a function and call that function on page refresh
Use the .live() functionality
Use .delegate() functionality
Put the Javascript reference to the functionality in a reference in the refresh so that it executes as a part of that refresh
Put the function in the callback
make it part of your setTimeout
some other creative method I did not think of...
Just a note: I would look at the .delegate() with contextual selection added in recent versions (available in 1.4.2 for instance).
Does load() not take a callback function as it's second argument? Why not reattach event handlers to the elements with that function?
$('#result').load('ajax/test.html', function() {
//reattach event handlers here.
});
So, you have a page:
<html><head>
<script type="text/javascript" src="jquery.1.3.2.js"></script>
<script type="text/javascript">
$(function() {
var onajax = function(e) { alert($(e.target).text()); };
var onclick = function(e) { $(e.target).load('foobar'); };
$('#a,#b').ajaxStart(onajax).click(onclick);
});
</script></head><body>
<div id="a">foo</div>
<div id="b">bar</div>
</body></html>
Would you expect one alert or two when you clicked on 'foo'? I would expect just one, but i get two. Why does one event have multiple targets? This sure seems to violate the principle of least surprise. Am i missing something? Is there a way to distinguish, via the event object which div the load() call was made upon? That would sure be helpful...
EDIT: to clarify, the click stuff is just for the demo. having a non-generic ajaxStart handler is my goal. i want div#a to do one thing when it is the subject of an ajax event and div#b to do something different. so, fundamentally, i want to be able to tell which div the load() was called upon when i catch an ajax event. i'm beginning to think it's not possible. perhaps i should take this up with jquery-dev...
Ok, i went ahead and looked at the jQuery ajax and event code. jQuery only ever triggers ajax events globally (without a target element):
jQuery.event.trigger("ajaxStart");
No other information goes along. :(
So, when the trigger method gets such call, it looks through jQuery.cache and finds all elements that have a handler bound for that event type and jQuery.event.trigger again, but this time with that element as the target.
So, it's exactly as it appears in the demo. When one actual ajax event occurs, jQuery triggers a non-bubbling event for every element to which a handler for that event is bound.
So, i suppose i have to lobby them to send more info along with that "ajaxStart" trigger when a load() call happens.
Update: Ariel committed support for this recently. It should be in jQuery 1.4 (or whatever they decide to call the next version).
when you set ajaxStart, it's going to go off for both divs. so when you set each div to react to the ajaxStart event, every time ajax starts, they will both go off...
you should do something separate for each click handler and something generic for your ajaxStart event...
Because you have a selector with two elements, you're creating two ajaxStart handlers. ajaxStart is a global event, so as soon as you fire any ajax event, the onajax function is going to be called twice. So yes, you'd get two popups.