jQuery's .on function doesn't seem to like 'load' event - javascript

I have a completely ajax driven website, so lately I've had to research delegation techniques. I've learned that .live and .delegate have been deprecated and the new function to use is .on .
If I'm dynamically loading a webpage into a division on the current page (AJAX) like so:
<html>
<head>
<script src="jquery.js">
</script>
<script>
function ajaxTest()
{
$('#content').load('test.php');
}
</script>
<script type="text/javascript">
$(function(){
$(document).on("click", "#map", function(){
alert("it has been loaded");
});
});
</script>
</head>
<body>
<div id="content">
<button onClick="ajaxTest()" value="Click Me">
This is to be clicked
</button>
</div>
</body>
</html>
where test.php looks like
<html>
<head>
</head>
<body>
<div id="map">THIS IS THE MAP</div>
</body>
</html>
I can then click on the words "THIS IS THE MAP" and it does indeed show the alert. The problem I've been having is instead of doing:
$(document).on("**click**", "#map", function(){
I need something more along the lines of:
$(document).on("**load**", "#map", function(){
It doesn't work obviously, so I'm wondering if something similar might. The whole reason I'm even inquiring about this is because in some pages, instead of having just "THIS IS THE MAP" in the map division, I have a google map or an swf object or something. Any help would be appreciated.
If you wanted to just answer how to load a google map into a division that doesn't exist yet, that would be helpful too ;)

Only some events bubble up the parent chain and can be used on parent objects with .on() or .live() or .delegate(). .load() is not one of those events that bubbles.
This is a partial list of events that bubble from the jQuery doc: click, dblclick, keydown, keypress, keyup, mousedown, mousemove, mouseout, mouseover, and mouseup.
From the doc page for .on(), here's a quote:
In all browsers, the load event does not bubble.
In your particular example, you can bind the event directly to the object like this:
$("#map").on("load", function(){});
or
$("#map").load(function(){});
When you bind directly to the object like this, no bubbling is needed and it will work with the load event. The object #map will need to exist at the time you bind the event handler as this method of using .on() or .load() can't work with objects that will be created in the future. The event handler must be attached to the object after the object is created.

if you want to do something when the response is loaded you can make use callback function in load instead of doing it in two separate script and event binding, something like
$('#content').load('test.php', function(){
alert("map is loaoded.")
});
reference

Related

How to reinitialize button that has been removed from the DOM?

So I'm running into an issue using a program called XCrud, that is supposed to help with database management. The gist of the issue is that the program removes and reinserts its buttons into the DOM, causing my click functions in JQuery to stop working.
$('a[class="btn btn-warning xcrud-action"]').on('click', function() {
intvId = window.setInterval(cleanup, 200);
});
This button is supposed to reset an interval that helps the user along the workflow of the database, but as aforementioned, the button will only trigger once.
Thanks for the help everyone
Use this syntax instead, to delegate the event handler to all members of the class, present and future:
$('parent').on('click', 'a.btn.btn-warning.xcrud-action', function() {
intvId = window.setInterval(cleanup, 200);
});
Where parent is an element higher up in the DOM tree than the a element you're targeting. (I'm assuming with this selector that all the classes in your example apply to a single a element.) This syntax supersedes the older delegate method.
The point is that you are attaching the handler to an element that isn't going to come and go (no matter how volatile your DOM is, you can always use document if you have to), and applying a filter (in terms of a selector) to the element to only apply the handler to the type of contained element that you want. As the doc states:
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time. By picking an element that is guaranteed to be present at the time the delegated event handler is attached, you can use delegated events to avoid the need to frequently attach and remove event handlers.
Unfortunately, the doc also fails to spell out that the [selector] argument of the on method delegates the handler to members of the classes in the selector. You can find that out by looking at the older delegate doc, and examining the examples that they give to convert from delegate to on.
Here's a little working example:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>
Test
</title>
<!--jQuery and jQuery-UI files-->
<script src="includes/jquery/jquery-2.2.3.js"></script>
<script src="includes/jquery-ui/external/jquery/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$('form').on('click', 'button.test1.test2', function(e, ui){
$('form').append('<button type="button" class="test1 test2">"Test"</button>')
alert('click');
});
});
</script>
</head>
<body>
<form>
<button type="button" class="test1 test2">Test</button>
</form>
</body>
</html>
Any new button will have the same behavior as the original one.

Javascript performance - Iterating over dom and adding listeners

I am currently working in a big web project where we have lots of dom elements which need a listener for click/change/... events. The first 500 lines of code of the main javascript file look like this.
$( ".bla" ).each(function(e) {
$(this).on("click", function(){
...
});
});
So basically we add like 100 listeners and for each listener we have to iterate over the complete dom tree. I think this will take up considerable computation power. Is there something like a best practice solution to avoid this?
You can use event delegation:
$(document).on("click", ".bla", function(){
// ...
});
Hopefully you learned from the other answers that there was no need to use each. However, there may not even be a need to select all elements with class .bla as in your example.
Rather, if a div, or some other element, contains all of the elements for which you are interested in handling a click event, you can put the event listener on the container, and then you determine which element got clicked by inspecting the target property of the event. This works due to 'event propagation' -- if not handled directly handled on the element you clicked, the event will propagate up the DOM.
Simple example below with just two buttons. This is straight Javascript which should easily enough be converted to JQuery -- hope it helps.
<html>
<head>
<script>
setTimeout(function() {
document.getElementById('container').addEventListener('click', function(event) {
alert('You clicked ' + event.target.innerHTML);
});
});
</script>
</head>
<body>
<div id="container">
<button id="fooButton" type="button">foo</button>
<button id="barButton" type="button">bar</button>
</div>
</body>
</html>

JQuery ClueTip with ColdFusion - Javascript $(document).ready() misfire [duplicate]

Yesterday I had an issue where a .on('click') event handler I was assigning wasn't working right. Turns out it's because I was was trying to apply that .on('click') before that element existed in the DOM, because it was being loaded via AJAX, and therefore didn't exist yet when the document.ready() got to that point.
I solved it with an awkward workaround, but my question is, if I were to put a <script> tag IN the ajax loaded content and another document.ready() within that, would that second document.ready() be parsed ONLY once that ajax content is done being loaded? In other words, does it consider that separately loaded ajax content to be another document, and if so, does having another document.ready() within that ajax-loaded HTML work the way I think it does?
Alternatively; what would be a better way to handle this situation? (needing to attach an event listener to a DOM element that doesn't yet exist on document.ready())
To answer your question: No, document.ready will not fire again once a ajax request is completed. (The content in the ajax is loaded into your document, so there isn't a second document for the ajax content).
To solve your problem just add the event listener to the Element where you load the ajax content into it.
For example:
$( "div.ajaxcontent-container" ).on( "click", "#id-of-the-element-in-the-ajax-content", function() {
console.log($( this ));
});
For #id-of-the-element-in-the-ajax-content you can use any selector you would use in $("selector"). The only difference is, only elements under div.ajaxcontent-container will be selected.
How it works:
As long as div.ajaxcontent-container exists all elements (if they exist now or only in the future) that match the selector #id-of-the-element-in-the-ajax-content will trigger this click-event.
Javascript in the resulting ajax call will not be excecuted (by default) due to safety. Also, you can't directly bind event to non-existing elements.
You can bind an event to some parent that does exist, and tell it to check it's children:
$(document).ready(function(){
$(document).on('eventName', '#nonExistingElement', function(){ alert(1); }
// or:
$('#existingParent').on('eventName', '#nonExistingElement', function(){ alert(1); }
});
Always try to get as close to the triggering element as you can, this will prevent unnessesary bubbling through the DOM
If you have some weird functions going on, you could do something like this:
function bindAllDocReadyThings(){
$('#nonExistingElement').off().on('eventName', function(){ alert(1); }
// Note the .off() this time, it removes all other events to set them again
}
$(document).ready(function(){
bindAllDocReadyThings();
});
$.ajaxComplete(function(){
bindAllDocReadyThings();
});
try this, that is not working because your control is not yet created and you are trying to attach a event, if you use on event it will work fine. let me know if you face any issues.
$(document).ready(function(){
$(document).on('click', '#element', function (evt) {
alert($(this).val());
});
});
The answer here is a delegated event:
JSFiddle
JSFiddle - Truly dynamic
jQuery
$(document).ready(function(){
// Listen for a button within .container to get clicked because .container is not dynamic
$('.container').on('click', 'input[type="button"]', function(){
alert($(this).val());
});
// we bound the click listener to .container child elements so any buttons inside of it get noticed
$('.container').append('<input type="button" class="dynamically_added" value="button2">');
$('.container').append('<input type="button" class="dynamically_added" value="button3">');
$('.container').append('<input type="button" class="dynamically_added" value="button4">');
$('.container').append('<input type="button" class="dynamically_added" value="button5">');
});
HTML
<div class="container">
<input type="button" class="dynamically_added" value="button1">
</div>
I'm working on a code-base with a friend that has a similar requirement. The delegated event handler option is definitely best if all you want is to attach event handlers. An alternative, especially if you need to do other DOM processing in your $(document).ready function, is to put the code you want run into a script element at the end of your code. Basically, instead of:
<script type="text/javascript">
$(document).ready(function() {
// Your code here
});
</script>
<!-- rest of dynamically loaded HTML -->
Try swapping the script and the rest of the HTML around so you have:
<!-- rest of dynamically loaded HTML -->
<script type="text/javascript">
// Your code here
</script>
This forces the browser to only process your code once it has loaded every other DOM element in the dynamically loaded HTML. Of course this means you'll have to make sure the inserted HTML does not have unintended UI consequences by using CSS/HTML instead of JS. Its an old Javascript trick from years gone by. As a bonus, you don't need jQuery for this anymore.
I should mention that in Chromium v34, putting a second $(document).ready call inside a <script> tag in the dynamically loaded HTML seems to wait for dynamically loaded DOM to load and then runs the function as you described. I'm not sure this behaviour is standard though as it has caused me great grief when trying to automate tests with this kind of code in it.
JQuery AJAX .load() has a built-in feature for handling this.
Instead of simply $('div#content').load('such_a_such.url'); you should include a callback function. JQuery .load() provides room for the following:
$('div#content').load('such_a_such.url',
{ data1: "First Data Parameter",
data2: 2,
data3: "etc" },
function(){ $('#span1').text("This function is the equivalent of");
$('#span2').text("the $(document).ready function.");
}
);
However, you do not need to include the data argument.
$( "#result" ).load( "ajax/test.html", function() {
alert( "Load was performed." );
});
http://api.jquery.com/load/

jQuery mouse events don't fire

I have a really strange problem. My example code works [here][1] quite fine, but I have the exactly same code in my aptana studio editor and when I try it in Chrome or the Eclipse browser the events just don't fire. I can't imagine what's the problem, because it's exactly the same code ...
HTML
<!DOCTYPE html>
<html>
<head>
<title>OrderScreen</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="js/script.js" type="text/javascript"></script>
</head>
<body>
Test
</body>
</html>
jQuery
$("a").mouseup(function() {
clearTimeout(pressTimer);
// Clear timeout
return false;
}).mousedown(function() {
// Set timeout
pressTimer = window.setTimeout(function() {
alert("hcbdhaf")
}, 1000);
return false;
}).click(function() {
alert("dfsdg");
});
If your code is really as quoted, the problem is that the elements don't exist as of when you try to hook event handlers to them. jsFiddle's default settings hide this problem from you. (Look on the left, and you'll see that your code isn't run until the load event fires — which is very, very late in the page load process.)
To fix it, either:
Move your script tags to the end of your document, just before or after the closing </body> tag. By the time the browser runs your script, the elements will exist. This is the recommendation of the YUI team and Google's web engineers like it too.
Use jQuery's ready event.
In conjunction with either of those, you might also look at using event delegation instead of directly hooking up events on the elements. Your mouseup and mousedown handlers will get attached to each a element individually. That's a lot of hookups. If there's a container that all of those a elements are in (body or better yet, something nearer), you might instead hook the event on that container (since those events bubble) and then check to see if the event originated in an a element. jQuery supports event delegation, doing most of the hard work for you, via delegate (which I like because it's so explicit) and more recently, one of the half-dozen variations of arguments you pass to on.

Why the jQuery events are not fired?

I thinkg I doing something wrong, but the events only works if the selector is document. Otherwise, not happens.
HTML
<html>
<head>
<!-- the libraries references here -->
</head>
<body>
<div id="canvas"></div>
</body>
</html>
Javascript
/* Click on canvas */
canvasClickEvent = function(e){
if(e.shiftKey){
selectedElement = $(this).attr("id");
}
}
/* Events */
$(document).ready(documentLoadEvent);
$(document).click(canvasClickEvent); //this works, but is wrong
//$("#canvas").click(canvasClickEvent); --this is what I want, but not works
$(document).dblclick(canvasDblClickEvent);
If I replace the document by the div name like $('#canvas').click(canvasClickEvent);, the click event is not called. It's only works if the selector is document, but the element passed to the function always has the attibs like undefined.
What might be happening?
What is happening is that event is attempting to bind the event before the DOM element exists.
If you wrap the events inside of the ready() method you guarantee that the domain exists before your event attempts to bind.
$(document).ready( function () {
$("#canvas").click(canvasClickEvent);
}
The ready() method is dependent on the browsers DOMContentLoaded event which basically means the DOM is completely loaded in the browser, but does not necessarily mean all the media on the page has completely loaded. Once all media is loaded the onLoad browser event fires.
It seems like you put your JavaScript code BEFORE the html code. So, when the JavaScript code runs, the elements to be dealt with is not loaded into the DOM yet. (That's why you got "undefined")
Just put your script AFTER the related HTML code. Or put it inside the pageLoad event:
$(function(){
....
})

Categories