I would do this in JS fiddle, but I can't get the POST echoer to work, so I'll make an example here. Let's pretend that someApi returns "bar"
JS / jQuery
$(function() {
$('button').click(function(event) {
getSomeData();
});
function getSomeData() {
$("div").text("Foo = ");
$.get("someApi", function(i) {
$("div").append(i);
});
};
});
HTML
<div></div>
<button>Click Me</button>
There maybe some typos here, but please ignore them as I've written an example on-the-fly. What happens is when <button> is clicked once, all works well. The AJAX function is called and the <div> is appended when the response comes. If I wait for the response and click again, the <div> is overwritten with Foo = and then appended. The issue comes when the user becomes inpatient and clicks <button> multiple times, spawning multiple AJAX requests. This ends up with "bar" being appended multiple times. Is there a feature within JS / jQuery to avoid sending multiple requests to the same URL? I DON'T mean I want a async = false scenario; I know this would work, but would also slow the application down. I also know I could add an if loop that checks if bar has already been appended. What I'm asking for is a proper JS / jQuery .blockMultipleRequest(); kind of thing.
I don't think that there's a plugin for that. You could use .one() in this way:
function bindButton() {
$('button').one('click', function(event) {
getSomeData();
});
}
function getSomeData()
$("div").text("Foo = ");
$.get("someApi", function(i) {
$("div").append(i);
bindButton();
});
}
$(function() {
bindButton();
});
In function bindButton() you define your event handler with one(). Once button has been clicked event is removed until response of AJAX call, then function bindButton() is called again and event handler gets bound again.
You could use the global AJAX event handlers that jQuery provides and then do stuff depending on the request.
.ajaxSend() when any request starts (the event, jqXHR, and settings properties are sent to the handler, so you can then do URL-specific actions by evaluating settings.url
.ajaxComplete() when any request completes.
You could then use an object that keeps track of AJAX calls per URL, which can consult before sending off another request (e.g. only if it not currently in an active/pending state).
Related
I have a page where I can insert some javascript / jquery to manipulate the output. I don't have any other control over the page markup etc.
I need to add an extra element via jquery after each present on the page. The issue is that the elements are generated via an asynchronous call on the existing page which occurs after $(document).ready is complete.
Essentially, I need a way of calling my jquery after the page has loaded and the subsequent ajax calls have completed. Is there a way to detect the completion of any ajax call on the page and then call my own custom function to insert the additional elements after the newly created s ?
Unfortunately this doesn't apply since it seems the OP isn't using $.ajax() or any jQuery ajax method for actually loading content, but leaving it here in case future googler's are doing this.
You can use any of the global ajax events that meet your needs here, you're probably after $.ajaxComplete() or $.ajaxSuccess().
For example:
$(document).ajaxSuccess(function() {
alert("An individual AJAX call has completed successfully");
});
//or...
$(document).ajaxComplete(function() {
alert("ALL current AJAX calls have completed");
});
If you want to run just some generic function then attach them to document (they're just events underneath). If you want to show something in particular, for example a modal or message, you can use them a bit neater (though this doesn't seem to be what you're after), like this:
$("#myModal").ajaxComplete(function() {
$(this).fadeIn().delay(1000).fadeOut();
});
This example just shows and hides elements at the start and end of ajax calls using jQuery:
$("#contentLoading").ajaxSend(function(r, s) {
$(this).show();
$("#ready").hide();
});
$("#contentLoading").ajaxStop(function(r, s) {
$(this).hide();
$("#ready").show();
});
#contentLoading is an gif image progress indicator.
As i could understand, you are using some jQuery's Ajax function in your ready handler. So you could just pass it another function, which will be invoked after your Ajax function gets response. For example
$(document).ready(function(){
$("#some_div").load('/some_url/', function(){
/* Your code goes here */
});
});
You could rewrite the send() function of the XMLHttpRequest object.
See a solution for doing just so using pure Javascript here.
You could use .live()/.delegate().
I didn't find any result for my issue.
I have Prestashop 1.5.6, I need to execute my jQuery function after blockcart adds the product.
BlockCart and my code starts with the same event, As I far know the unbind disables the other handlers event, how can I restart the unbind in the footer code?.
So my code don't work because Blockcart starts on first
//---------BlockCart Code---------
overrideButtonsInThePage : function(){
//for every 'add' buttons...
$('.ajax_add_to_cart_button').unbind('click').click(function(){
var idProduct = $(this).attr('rel').replace('nofollow', '').replace('ajax_id_product_', '');
if ($(this).attr('disabled') != 'disabled')
ajaxCart.add(idProduct, null, false, this);
return false;
});
//for product page 'add' button...
$('#add_to_cart input').unbind('click').click(function(){
ajaxCart.add( $('#product_page_product_id').val(), $('#idCombination').val(), true, null, $('#quantity_wanted').val(), null);
return false;
});
//-------- Footer code--------
$('.button.ajax_add_to_cart_button.exclusive, .button.ajax_add_to_cart_button.btn.btn-default').on('click',function(){
var id_product = $(this).attr('data-id-product');
myfunction(id_product);
});
It's possible to detect when blockcart ends the script without a editing the blockCart module with a callback function?
Thanks!
Finally the result was an override the blockCart function.
I did a copy of the overrideButtonsInThePage into my js to override it and I add my code inside the events.
Works perfectly
Depending on how blockcart functions, you can try:
//-------- Footer code--------
$('.button.ajax_add_to_cart_button.exclusive, .button.ajax_add_to_cart_button.btn.btn-default').click(function(){
var id_product = $(this).attr('data-id-product');
setTimeout(function() { myfunction(id_product); }, 0);
});
This will cause your function to execute after the existing stack finishes executing. You can learn more about what this does in Why is setTimeout(fn, 0) sometimes useful?. This will only be helpful if the blockcart handler is synchronous.
You can actually monitor ajax calls by using $.ajaxComplete(); and .ajaxStart()
http://api.jquery.com/ajaxcomplete/
What you can do is compare url the ajax is being sent to. Add to cart URL has GET parameters pre-encoded into it, so distinguishing it from other ajax calls isnt hard. Then on $.ajaxComplete(); you should compare the response result (determin that it was a succes) and then execute your function. This way you wont modify anything, you will just be observing the ajax actions
I have 3 <select> menus, each with change events working on them. Break down of the code looks like this:
$(document).ready(function(){
// some code
$("#selectOne").change(function() {
// some code inc ajax request
$("#selectTwo").change(function() {
// some code inc a different ajax request
});
$("#selectThree").change(function() {
// some code inc a yet another ajax request
});
});
});
The problem with the above is that, while selectOne works fine, and selectTwo seems to work fine also, if I change selectThree, the code for both selectTwo AND selectThree fires at the same time. Depending on the sequence of selection of any of the 3 selects, the response of selectThree.change can be to display and hide each of the previous responses, before settling on displaying an incorrect response.
What I'd like to do is this:
$(document).ready(function(){
// some code
$("#selectOne").change(function() {
// some code inc ajax request
});
$("#selectTwo").change(function() {
// some code inc a different ajax request
});
$("#selectThree").change(function() {
// some code inc a yet another ajax request
});
});
In this scenario, selectOne works fine, but selectTwo and selectThree don't respond to change.
Is there a way of correcting any of this, so that as each element is changed, only the correct change event is fired?
It seems that when your document is loaded there is no select elements with id "selectTwo" or "selectThree". Similarly in the first case, there is no "selectThree" when the eventhandler of "selectOne" executes. That's why the corresponding event handlers does not execute. There is two way you can handle this proplem.
1 - Assing handlers when the elements are created.
2 - Use .on() instead of .change():
$('body').on("change", "#selectOne", function () {});
$('body').on("change", "#selectTwo", function () {});
$('body').on("change", "#selectThree", function () {});
I am trying to use the jQuery $.post method to submit an ajax request to a PHP script whenever a certain element is clicked. I don't care about the value returned by the server - I just want to make sure that my data is submitted.
However, the element that receives the click could contain either a hyperlinked image or a flash element with several links in it. How can I ensure that my script receives the post request (again, I don't care about its response) even if the user navigates away from the page? I am using the code below:
jQuery(document).ready(function($) {
$(".click-track").mousedown(function(e) { // click() will not pass through a flash movie, so we must use mousedown
ad_id = $(this).data("ad-id");
var data = {
action: 'log_click',
adId: ad_id
};
$.ajaxSetup({async: false});
$.post(myscript.php, data, function(data) {
// Do nothing because we don't care about the response
}, 'html');
});
});
I'm no browser scripting guru, and this code has me flummoxed. I would appreciate any help you could give!
If you do an e.preventDefault() within the mousedown handler, you can simply do this inside the $.post call:
$(".click-track").mousedown(function(e) { // click() will not pass through a flash movie, so we must use mousedown
e.preventDefault();
ad_id = $(this).data("ad-id");
var data = {
action: 'log_click',
adId: ad_id
};
$.ajaxSetup({async: false});
var jqxhr = $.post(myscript.php, data, function(data) {
// Do nothing because we don't care about the response
}, 'html');
jqxhr.complete(function(){ $(this).trigger('click'); });
});
This should create an ajax object and attach a function when the POST request completes that should trigger a click on the originally mousedown'd element. I've gotten this to work with non-Flash elements, not sure if it will work on the Flash object, but it should.
Handle the redirect in Javascript, and make it happen after you get a response. Also, you probably don't want AJAX -- you probably want a synchronous post.
If you want to force you code to block until the post finishes, I suggest using .ajax() instead and set the async field to false. Like so:
$.ajax({
//some fields
async:false,
//some more fields
});
Now, your js will block until the call returns. Though I will warn you this is not preferred.
Edit: If the element is a hyperlink you will need to call event.preventDefault(). It is also worthwhile to set the link's href attribute to "javascript:void(0);".
So I have a normal link on my website, and I want to add tracking for it. I could envision a bunch of ways to do this, but I've settled on this as being really easy by writing a small jquery function, and dropping a small snippet in my tags:
click me!
javascript:
function saveClick(someparamhere){
$.ajax({
url: "somepage.php",
data: {param:someparamhere}
});
}
Now, I know my syntax might be bad, I'm just asking about the overall concept here. When you click the link, I want javascript to issue the call to saveClick which immediately makes an ajax call. There's no success handler because I don't really care if or what gets returned. I'll just have somepage.php log the event. Then, after all of that, I want the tag to go to it's href.
Is that the case? Will the ajax call be issued before the document goes to the other page? Will this work in all cases?
Has anybody ever done something like this? Any experience would be appreciated ....
If you want to make sure the AJAX call goes through you could do:
click me!
$('[data-parameters]').bind('click', function (event) {
//cache this element to use in AJAX function
var $this = $(this);
//prevent the default naviation
event.preventDefault();
$.ajax({
url: "somepage.php",
data: {param:$this.attr('data-parameters')}
success : function () {
//now navigate to the requested page
location = $this[0].href;
}
});
});
UPDATE
$.ajax() exposes a timeout function:
timeoutNumber
Set a timeout (in milliseconds) for the request. This will override
any global timeout set with $.ajaxSetup(). The timeout period starts
at the point the $.ajax call is made; if several other requests are in
progress and the browser has no connections available, it is possible
for a request to time out before it can be sent. In jQuery 1.4.x and
below, the XMLHttpRequest object will be in an invalid state if the
request times out; accessing any object members may throw an
exception. In Firefox 3.0+ only, script and JSONP requests cannot be
cancelled by a timeout; the script will run even if it arrives after
the timeout period.
So you could set a timeout and an error function that mimics the success function. The documentation does state that: it is possible for a request to time out before it can be sent but if your timeout is a very small (maybe zero) delay then it could reduce the lag between the user clicking the link and the browser loading the new page.
I simply wouldn't do that... it could bring to situation your onclick event isn't fired.
I think it would be better to call a javascript function on click that does your ajax call and then bring the user to the target page.
You can do this, for example, this way:
...
your javascript function then, shall be something like:
myfunc(paramofpageclickhere) {
//do ajax call
saveClick(someparamhere);
//go to target page
location.href = "target.htm";
}