I have the following jQuery code which watches for an ajax request and then shows / hides a spinner image when the request starts / ends.
This works fine on page load. However if I update part of the page with a new ajax link, this code no longer catches the ajax:before. Does anyone know if there is a solution to this without having to call unbind() and then re-call the code again?
$("*[data-spinner]").on('ajax:before', function(e) {
$('#' + $(e.target).data('spinner')).show();
});
$("*[data-spinner]").on('ajax:complete', function(e) {
$('#' + $(e.target).data('spinner')).hide();
});
Did you tried like
$("body").on("'ajax:before", "*[data-spinner]", function(){
$('#' + $(e.target).data('spinner')).show();
});
$("body").on('ajax:complete', "*[data-spinner]", function(e) {
$('#' + $(e.target).data('spinner')).hide();
});
$(document).on('ajax:before', '*[data-spinner]', function(e) {
$('#' + $(e.target).data('spinner')).show();
});
This is because jQuery binds its functions to the DOM on the pageload. If you try to bind your "data-spinner" that is not there yet jQuery will not find it and wont bind it.
However if you bind on document it can be found and we pass your '*[data-spinner]' as a 2nd parameter since its just a filter. jQuery will watch it only when you click something inside "document" so it will always be up-to-dated.
It should be something like
$(document).on("ajax:before", "*[data-spinner]", function(){
//...
});
Or you can use the parent element instead of document and it's better/faster, i.e.
$('#parent_element').on("ajax:before", "*[data-spinner]", function(){
//...
});
The prototype is
.on( events [, selector ] [, data ], handler(eventObject) )
Read more on jQuery website.
Related
I've been having some trouble with this block of code, and I think I've finally narrowed the problem down. Here's the jQuery function...
$(document).ready(function(e) {
$('#formattingSection').load ('formattingdoc.html #formatting');
$('#loadFormatting').click(function() {
$('#formattingSection').load ('formattingdoc.html #formatting');
});
$('#loadSmileys').click(function() {
$('#formattingSection').load ('formattingdoc.html #smileys');
});
$('#formattingSection div img').click(function() {
var code = $(this).attr("title");
alert (code);
$('wallpost').val($('wallpost').val() + code);
});
});
Basically, it works like this. The page loads, we load part of a doc via AJAX. There are four buttons on the page, each one loads a new section via AJAX. When you click #loadSmileys, it will load via AJAX several images and display them in the DIV.
I'm binding a click() event to those images... but what I've found is that since the images aren't on the page at load time, the click event never gets bound. When I strip all the code away and load the images without AJAX, the click binds okay.
So... my question here... is there a way to bind the click event to the images AFTER they are loaded via AJAX?
For reference... I did make a jsBin HERE, but it's basically just hard coding the images to that I can see it works without the AJAX stuff going on.
Try:
$("#formattingSection").on("click","div img",function() {
var code = $(this).attr("title");
alert (code);
$('wallpost').val($('wallpost').val() + code);
});
As $.on attaches event handler to the parent and all events from children are delegated to the parent
Documentation
Yes, you totally can attach event handles to DOM nodes loaded on-the-fly. The trick is to use jQuery.get instead of .load. .get allows you to add an additional callback function that gets executed upon AJAX completion - the perfect place for you to add your $("#formattingSection div img") code. Here's what it would look like:
$('#loadSmileys').click(function() {
$('#formattingSection').get ({
url: "formattingdoc.html",
success: success
});
});
function success() {
$('#formattingSection div img').click(function() {
var code = $(this).attr("title");
alert (code);
$('wallpost').val($('wallpost').val() + code);
});
}
$('#formattingSection').load ('formattingdoc.html #formatting', function( response, status, xhr ) {
loading_completed();
});
function loading_completed()
{
$('#formattingSection div img').click(function() {
var code = $(this).attr("title");
alert (code);
$('wallpost').val($('wallpost').val() + code);
});
}
Try this
$('#loadSmileys').click(function() {
$('#formattingSection').load ('formattingdoc.html #smileys', function() {
$('#formattingSection div img').click(function() {
var code = $(this).attr("title");
alert (code);
$('wallpost').val($('wallpost').val() + code);
});
});
});
You should use the 'on' method. This can apply click handlers to elements created after the on method is called.
e.g.
$("#formattingSection").on("click","div img",function() {
...
}
As imges are added, they will automatically get the click handler functionality.
This question I asked helps explain the difference: jquery use of bind vs on click
I have a function that when it runs new markup is generated on the fly...
$('.search input[type="image"]').on('click', function(){
// Open directions in a map
if($('#TXT_SAddr').val() === ''){
return false;
$('.directions .search').css('background' , '#ff0000');
} else {
var from = $('#TXT_SAddr').val();
var to = $('.postal-code').html();
var directions = 'http://maps.google.com/maps?saddr=' + from + '&daddr=' + to + '&output=embed';
var modal = '<div class="apply-modal modal"><a class="close-apply-now" style="margin-bottom: 20px;"><img src="http://site.co.uk/images/closeModal.png" alt="Close" style="border-width:0px;"></a><div class="holder"><iframe src="'+directions+'" style="border:none; width:100%; height:500px;" border="0"></iframe></div></div>';
$('body').prepend('<div class="modalOverlay"/>' + modal);
$('.modal').animate({
'opacity': 1,
'top': '100px'
}, 700, 'easeOutBack');
}
return false;
});
If you can see, the above generates a div with an anchor under the class name of 'close-apply-now'.
I now want to bind a function to this and I've tried using...
$('a.close-apply-now').on('click', function(){
alert('asdasd');
});
with no luck, can anybody see where I may be going wrong? Not even my alert is working.
Since the close-apply-now div is added dynamically, you need to use event delegation to register the event handler like:
// New way (jQuery 1.7+) - .on(events, selector, handler)
$('body').on('click', 'a.close-apply-now', function(event) {
event.preventDefault();
alert('asdasd');
});
This will attach your click event to any anchors with class close-apply-now within the body element.
The syntax for event delegation is slightly different.
The event need to be bind to an element which is already existing in the dom while the target element selector needs to be passed as the second argument
$(document).on('click', 'a.close-apply-now', function(){
alert('asdasd');
});
The close-apply-now div is added dynamically. You have to add the selector parameter, otherwise the event is directly bound (doesn't work for dynamically loaded content) instead of delegated. See http://api.jquery.com/on/#direct-and-delegated-events
Change your code to
$(document.body).on('click', '.update' ,function(){
The jQuery set receives the event then delegates it to elements matching the selector given as argument. This means that contrary to when using live, the jQuery set elements must exist when you execute the code.
Use jQuery's live() method. Description: Attach an event handler for all elements which match the current selector, now and in the future.
$("a.close-apply-now").live("click", function(){
alert('asdasd');
});
Try Both in Jsfiddle
I currently have a script that I am using in my website. The goal of the script is when the user clicks the link, the javascript function will fire. This function is based off of the div id. At the end of the function I use jquery to change said div id. However, when the user clicks the link again the function still fires, even though the id has changed. What am I doing wrong? How can I get the script to only execute the first time the link is clicked?
$("#down").click(function(){
var id = $("#down").attr("class");
$.ajax({
type: "POST",
url: "vote.php",
data: "side=down&id=" + id,
success: function(){ alert("lul worked"); }
});
$('.' + id + '#down').attr('id', 'down_stay');
});
Now that you all have answered, what is the better choice, using "one" or using "unbind"?
Don't use click, use on. Or in your case, one:
$('#down').one('click', function() {
// function only fires once and then is unbound.
});
Use $("#down").one("click", function(){}); instead to make it fire only once.
Use unbind() instead.
replace
$('.' + id + '#down').attr('id', 'down_stay');
with
$( this ).unbind( 'click' );
Try using one
$("#down").one('click', function(){
The DOM events are attached to the elements and not to the attributes.
So even if you change the attributes of the element it does not mean it is a different element.
The event will only be removed if that particular element will be removed from the DOM..
I know you can bind to click events with jQuery like so:
$('a').click(function(){});
But what about html elements that are added dynamically? Lets say I have a div with the following contents:
<div>
<a href='location.html'>location</a>
</div>
Now I call:
$('a').click(
function(){
console.log("going to " + $(this).attr('href'));
return true;
});
And that will work fine. But if somewhere along the line I call
$('div').("<a href='location2.html'>location2</a>");
without explicitly binding that event handler to that event then the event handler will pick up on it.
Is it possible to rebind when ever a new a element is added. Or even better, when ever the location.href property is changing so I can add a get parameter to it every time.
For example if I was binding to a click event on an a element the event handler would be:
function(){
var newid = parseInt(Obj.Request('pageid'), 10) + 1;
location.href = $(this).attr('href') + '?pageid=' + newid.toString();
return false;
}
Assuming the Obj.Request is a function that returns a get parameter. (I already have this in place).
Use it in this manner:
$(document).on( 'click', 'a', function() {
console.log("going to " + $(this).attr('href'));
return true;
});
Working on your fiddle link.
You want to use the function .on.
$('a').on('click', function() {
//works on non dynamic elements present at page load
});
$('#some_non_dynamic_parent_ID').on('click', 'a', function() {
//works on dynamic elements added later
});
You want to use .on(), but as a delegation method.
Bind it to the closest static parent - for this example I'll just use body.
$('body').on('click', 'a', function(e){
e.preventDefault();
});
This will wait until the event bubbles up to the body element and check what the original target of the event was - if it was an a element, it'll fire the handler.
You can use .on() or live() functions if you use jquery upper then 1.7 version. About the difference of these functions you can read in this article
The scenario
I'm getting a page by JQuery ajax call, and show as a pop-up. The reason why i'm doing so is the page can be accessed without javascript also. The page itself contains some drop-down lists and buttons. In the javascript disabled version the state of the page maintained by passing the selected values to and from the server which uses php. Therefore i intended to do the same with the javascript and in such case the previous html elements need to be replaced with ajax response. I made an extensive search over the web, but helpless.
The problem
After replacing, the elements losing their event data,
how to preserve or re-bind the events associated with them?
The code i have been trying to implement is
$('#search-main a').on('click', function(e){
e.preventDefault();
$('#search-advanced').remove();
var target = $(this).attr('href');
var res = $.get(target, function(data){
$('body').append($(data).find('#search-advanced'));
$('#search-advanced').addClass('row reveal-modal');
$('#search-advanced')
.css('top', 80)
.css('border-radius' , '5px')
.css('padding-left' , '0px')
.css('padding-right' , '0px');
$('#search-advanced input[name="select_filter"]').remove();
$('#search-advanced .custom.dropdown').on('change', function(){
$('#search-advanced form').trigger('submit');
});
$('#search-advanced form').on('submit', function(e){
e.preventDefault();
var params = $('#search-advanced form').serialize();
$.get(target, params, function(data){
// This is where I'm encountering the problem
// The first time it works fine,
// but for the second time the change event not get triggered
$('#search-advanced form').replaceWith($(data).find('#search-advanced form'));
$('#search-advanced input[name="select_filter"]').remove();
console.log($(data).find('#search-advanced .custom.dropdown'));
});
});
$('#search-advanced').append('<a class="close-reveal-modal">×</a>');
$('#search-advanced').reveal({
animation: 'fade',
closeOnBackgroundClick: false
});
});
});
I'm not sure about the elegance of this approach, any suggestion to solve or different approach will be very thankful.
I already tried the following links
jQuery event not triggered
jQuery load-event after replaceWith
Maintain jQuery onChange After a Replacewith
I'm not sure why you're destroying the original form in the first place. If you just need to reset it, there are probably better ways.
But given that you are destroying the form, and therefore its handlers, you could bind the handler to the #search-advanced element, and use the event delegation signature of .on.
// v--event is bound here v--and will trigger on the form element
$('#search-advanced').on('submit', "form", function(e){
e.preventDefault();
var params = $('#search-advanced form').serialize();
$.get(target, params, function(data){
$('#search-advanced form').replaceWith($(data).find('#search-advanced form'));
$('#search-advanced input[name="select_filter"]').remove();
console.log($(data).find('#search-advanced .custom.dropdown'));
});
});
Try binding the event like this:
$(document).on('click', '#search-main a', function(ev){
// your code
});