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
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 think it very stupid question, but after hours of google it - i have no idea or solution.
Point is that i need reload page after handling "click" event on my web-site. In chrome\opera it's works without problems. But in firefox i have some bug. My JS code with comments:
$('#project_create').click(function() {
var projectname = $("#project_name").val();
var projectdescription = $("#project_description").val();
$.post("projects/add_project.php", {
project_name: projectname,
project_description: projectdescription
});
$("#create_project_form").hide("slow");
$("#project_list").show("slow");
//return false; - if it uncomment, all work, but next page reloader doesn't work.
window.location.reload(); //but if it's work, FireFox doesn't send $.post-query
});
I need to work booth methods, because after click - script put in $_SESSION['my_var'] some variable, and it variable is avaliable after reload page only. Maybe there are other ways to do it? As I understand the problem here in features with firefox and preventDefault();
Thanks!
The issue is just you reload the page before performing the ajax request.
Try to reload page in the ajax success callback handler :
$.post("projects/add_project.php", {
project_name: projectname,
project_description: projectdescription
}, function(){
window.location.reload();
});
And remove your old window.location.reload()
When you do a return, code after that line will not be reached anymore and is considered "dead code". One does not simply put code after a return.
Another is that there's and issue when using return false to prevent default default actions. It prevents delegation/bubbling. Event handlers hooked higher up in the DOM tree (especially ones hooked with on()) won't be executed. If delegation matters, don't use it.
If your goal is to prevent the default action of the link and do stuff in JS, use event.preventDefault instead. The event object is passed in as the first argument in the handler.
$('#project_create').click(function(event) {
event.preventDefault();
// rest of the code
});
In addition to what the other answers suggest, you can also execute the location.reload method asynchronously using setTimeout:
setTimeout(function() { location.reload(); }, 1);
return false;
EDIT: The entire idea of running an asynchonous AJAX request and reloading the page immediately afterwards is flawed, of course, since the AJAX request may not have been completed by the time you reload the page.
You should therefore use a callback, as suggested by the accepted answer. Alternatively, you could use a synchronous AJAX request, but that would freeze execution until the request has completed, which is generally not desirable.
I have a lot of buttons with the class search_camera_btn.
When clicking on the button then it submits a form. This step works. On the other side, it should also trigger a button click event.
I wrote the event listener in a coffeescript file which sends Ajax requests, but it only works on the first click.
I put the code in this gist.
The Javascript works when the button is clicked the first time, but fails on subsequent clicks.
Actually I put a alert message in the begin of click event handler,
But it only alerts at the first time.
And there is no error message in my Firbug console. (I thought it is just didn't fire the click event handler.)
$(".search_camera_btn").click ->
alert "test"
There are many buttons,no matter which button I click.
It always works at the first time click.
Here is my more detail source code. download
Any ideas?
I narrow down the buggy code.That is the "Ready to enter start" message only called at the first time.
But there is no error showed on the Firebug Javascript console and Rails console.
Should I enable some settings in the development mode ?
IW2 = get_camera_list: ->
console.log("Start")
ajax_req = $.ajax
url: "update_camera_list/"
type: "GET"
success: (resp) ->
# console.log resp
res = setTimeout (->
ajax_req
), 500
console.log("End")
return
jQuery ->
$(".search_camera_btn").click ->
console.log("Ready to enter start")
IW2.get_camera_list()
Compiled CoffeeScript:
var IW2;
IW2 = {
get_camera_list: function() {
var ajax_req, res;
console.log("Start");
ajax_req = $.ajax({
url: "update_camera_list/",
type: "GET",
success: function(resp) {}
});
res = setTimeout((function() {
return ajax_req;
}), 500);
console.log("End");
}
};
jQuery(function() {
return $(".search_camera_btn").click(function() {
console.log("Ready to enter start");
return IW2.get_camera_list();
});
});
The reason that the handler is only being fired once is because
the ".click" handler only applies to elements that are currently attached
to the DOM. If you replace the HTML after making the AJAX call, the event handlers will be lost.
You should use an event delegate instead. Try this:
jQuery(function() {
return $("body").on("click", ".search_camera_btn", function() {
alert("Ready to enter start");
return IW2.get_camera_list();
});
});
This statement basically says, if there are any elements in the DOM now, or in the future, that have a class of "search_camera_btn", and are contained within the "body" element, then fire the click handler.
I hope this helps!
Change this:
jQuery ->
$(".search_camera_btn").click ->
console.log("Ready to enter start")
IW2.get_camera_list()
For:
jQuery ->
$(".search_camera_btn").click ->
console.log("Ready to enter start")
IW2.get_camera_list()
return
And let me know if it helps ;)
I would make sure nothing else in your application's javascript is failing (like a simple syntax error can cause this sort of thing). Also have you tried this in different browsers? I've had a similar problem where my Ajax would work fine in Chrome but would only post once in Firefox because of some add-ons/extensions (and then I disabled them and they worked).
Also, I'm not sure if I read your gist correctly but it looks like you're specifying .click in both the jQuery of the application.js and in the btn.js.coffee, and I'm pretty sure that section in application.js should just be watching for the element's function/result and not specifying the click again.
If nothing else works, also check out ajax's .done completion call about halfway down the page here: http://api.jquery.com/jQuery.ajax/ . Then show the picture list as a function after .done so you know your ajax post is always completing before moving on to the next thing. (Ajax problems like this often tend to be server side when a call doesn't complete or there's a loop somewhere)
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).
We're creating a click tracking app, that builds heatmaps. I'm writing a script which users are suppose to insert into their pages for tracking to work.
It works fine on elements, which doesn't require a redirect or form submit. For example, if I click on h1 or p or whatever, it works perfectly correct. But, if I click on a a, request to our server never happens before the normal redirect.
In the last couple of days I tried a lot of ways to do that. First of, I tried a normal AJAX call, since it was a cross-domain request I had to use JSONP, but again, that AJAX call did not have time to execute before the redirect. Adding async: false would have solved the problem, but it doesn't work with JSONP requests. So I decided to add a flag variable which indicates that it is safe to move on with redirect and used an empty while loop to wait until it becomes try in the ajax callback. But the while loop was blocking the execution flow, so callback never got a chance to set that variable to true. Here is some simplified code:
$(document).on('click', function (e) {
//part of the code is omitted
$.ajax({
url: baseUrl,
data: data,
type: "get",
dataType: "jsonp",
crossDomain: true,
complete: function (xhr, status,) {
itsSafeToMoveOn = true;
}
});
while(!itsSafeToMoveOn){}
return true;
});
The next thing I tried is to use unload page event to wait until total ajax calls in progress would become zero (I had a counter implemented) and then to move on with redirect. It worked in Firefox and IE, but in WebKit there was this error:
Error: Too much time spent in unload handler
After that I realized that I don't care about the server response and using img.src for the request would be an ideal fit for this case. So at this point code looks like this:
$(document).click(function (e) {
//part of the code is ommited
(new Image).src = baseUrl + '?' + data;
if (tag === "a" || clickedElement.parents().has("a")) {
sleep(100);
}
return true;
});
That way I increased the overall script performance slightly, but problem with links remains unchanged. The sleep function appears to be also blocking the execution flow and request never happens.
The only idea left is to return false from the event handler and than redirect manually to the clicked element's href or to call submit() on the form, but it will complicate things to much and believe me it's already a huge pain in the ass to debug this script in different browsers.
Does anyone have any other ideas?
var globalStopper = true;
$(document).on('click', function (e) {
if (globalStopper === false)
return true; //proceed with click if stopper is NOT set
else {
globalStopper = false; //release the breaks
$.ajax({
//blahblah
complete: function (xhr, status,) {
$(elem).click(); //when ajax request done - "rerun" the click
}
});
return false; //DO NOT let browser process the click
}
});
Also, instead of adding image, try adding script. And then add the script to the HEAD section. This way the browser will "wait" until it's loaded.
$(document).on('click', function (e) {
var scriptTag = document.createElement("script");
scriptTag.setAttribute("type", "text/javascript");
scriptTag.setAttribute("src", url);
document.getElementsByTagName("head")[0].appendChild(scriptTag);
return true;
}
I would take a look at the navigator sendBeacon API mentioned in this stack overflow answer or directly linked to here.
From the description on the site
navigator.sendBeacon(url, data) - This method addresses the needs of analytics and diagnostics code that typically attempts to send data to a web server prior to the unloading of the document.
You can save information to ajax request in cookies or localStorage and make any worker that will send information. Saving to cookies or localStorage is faster then ajax-request. You can do next:
$(document).click(function (e) {
var queue = localStorage.getItem('requestQueue');
queue.push(data);
localStorage.setItem('requestQueue',queue);
});
$(function(){
setInterval(function(){
var queue = localStorage.getItem('requestQueue');
while (queue.length > 0) {
var data = queue.pop();
$.ajax({
...
success: function(){
localStorage.setItem('requestQueue', queue);
}
});
}
},intervalToSendData);
});
So, when user click on link or send a form, data will be saved to storage and after user go to next page, this worker starts and send data to your server.
The JavaScript is basically executed in single thread. It is not possible to have your callback function executed and at the same time have an infinite loop waiting for a flag variable from it. The infinite loop will occupy the single execution thread and the callback will never be called.
Best approach is to cancel the default handler of your event and bubbling for it (basically return false if you are really building your tracking code with jQuery), and do the necessary actions (redirect page to the necessary address if a link was clicked or trigger other default actions), but this would take a lot of careful work to recreate all the possible combinations of actiona and callbacks.
Another approach is to:
1) Look for something specific to your code in the event data
2) If it is not present - make an AJAX call and in its callback re-trigger the same even on the same element, but this time with your specific bit added to the even data; after the AJAX call return false
3) If your specific bits are present in the data - simply do nothing, allowing the default event processing to take place.
The either approach may bite, however.
So if I understand right, you want your ajax logs completed before the page unloads and follows a link href. This sounds like a perfect case where you could consider using Deferreds in jQuery.
When your user clicks on anything that's supposed to take him away from the page, just check your promise status. If it's not resolved, you could throw a modal window over the page, and ask the user to wait til the progress is complete. Then, add a new pipe to your deferred, telling it to change the location href once everything is complete.
Let me know if this is the scenario. If it is, I'll explain in more detail. No use continuing if I didn't understand your requirement properly