Execute a second .click() event after the first is done - javascript

I would like to "chain" two .click() calls but cannot get it to work.
The code does work when I debug the JS code in my browser (so with a delay it seems to work)
I somehow need the first .click() to load the page (that's what the first event does) and only if that is done, I want the second .click() to execute.
My Code:
$.post("settings?type=mail&nr=" + nr, function(data){
if(data != ""){
alert(unescape(data));
// First click event -> realoads the page
$("#change_settings").click();
// Second click event -> navigates to a tab
// inside the page loaded by the first click event
$("#tab_mail_header" + nr + "").click();
}
});
EDIT: More Code
function load_change_settings_view(e){
e.preventDefault();
$("#content").empty();
// load settings.jsp in a div (test) inside the mainpage
$("#content").load("settings.jsp #test", function(){
// In here are a couple of .click() & .submit() functions but nothing else
});
});
$("#change_settings").click(function(e){
load_change_settings_view(e);
});
EDIT: I currently have this code:
$("#change_settings").click();
window.setTimeout(function () {
$("#tab_mail_header" + nr + "").click();
}, 1000);
I dont really like it though, as it is a timed delay and it may be the case (on a slow client) that that 1 second timeout will not be enough. I don't want to set the timeout too high as this slows down the workflow for users with a faster client...
I looked though a couple of post like these:
JQuery .done on a click event
Wait for a user event
How to wait till click inside function?
Wait for click event to complete
Does anyone have an idea on how to get this to work?

after a few more attempts I ended up with the following solution:
Code Snippet#1
$.post("settings?type=mail&nr=" + nr, function(data){
if(data != ""){
alert(unescape(data));
// create event object
var evt = document.createEvent('MouseEvents');
evt.initEvent('click', true, false);
// call method manually (not called by actual button click like its supposed to be)
// - pass event object
// - additional parameter to specify the tab the user is viewing
load_change_settings_view(evt, "tab_mail_header" + nr);
}
});
Code Snippet#2
function load_change_settings_view(e, p_tab){
e.preventDefault();
$("#content").empty();
// load settings.jsp in a div (test) inside the mainpage
$("#content").load("settings.jsp #test", function(){
// Go to previous tab (if one was selected)
var prev_tab = p_tab;
if(typeof prev_tab != 'undefined'){
$("#" + prev_tab).click();
}
// In here are a couple of .click() & .submit() functions but nothing else
});
});
feel free to comment if you have a better idea on how to solve this problem or if you have any other suggestions

Related

Jquery Execute function After third party function ends

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

Button click does not fire on second click

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)

Delaying click event

I'm wondering whether there's a simple way to delay the click event from being processed for a specified period of time. For example we could have
$('#someElement').on('click', 'a', function(event) {
var duration = 1000;
someAsynchronousFunction(); // Start as soon as click occurs
... // Code to delay page transition from taking place for duration specified
});
So in this case the asynchronous function would be guaranteed some amount of time to run. If it hasn't completed it's work in this time I wouldn't care and would just like to continue with the page transition. I know that it's possible to accomplish something close with
event.preventDefault();
...
setTimeout(function(){
window.location = $(this).attr('href');
}, duration);
But this only works when the link being clicked goes to a full page. I want to be able to deal with links that are used for ajax calls (which don't change the url) as well.
I noticed that the mixpanel library has a function track_links which seems to accomplish the delay on the page transition, though that function doesn't seem to work well with the support for ajax links that I mentioned.
Any help would be great! Thanks.
Edit: So I suppose my question wasn't exactly clear, so I'll try to provide some more details below.
I don't care if the async function finishes running! I only want to give it the guarantee that it has some set amount of time to execute, after which I don't care if it finishes, and would prefer to go ahead with the page transition.
i.e. I want to delay not the start of the async function, but the start of the page transition. The async function would start running as soon as the click occured.
Hopefully this is a bit more clear!
I figured out a way to solve the problem:
var secondClick = false;
var duration = 1000;
$('#someElement').on('click', 'a', function(event) {
var that = $(this);
if(!secondClick) {
event.stopPropagation();
setTimeout(function(){
secondClick = true;
that.click();
}, duration);
someAsynchronousFunction();
} else {
secondClick = false;
}
});
When the user clicks the link, it internally prevents that click from actually having any effect, and gives the asynchronous function a set amount of time to do it's work before doing a second click on the link which behaves normally.
setTimeout allows you to delay running code by however many ms you want
setTimeout(function(){
console.log('Stuff be done'); //This will be delayed for one second
}, 1000);
In reality, if you're dealing with ajax you want to respond when the ajax call is complete. It may take more or less than 1000ms. $.ajax allows you do this with the .done() method. This is an example from the docs:
$.ajax({
url: "test.html",
context: document.body
}).done(function() {
$(this).addClass("done");
});
window.setTimeout will execute any given function after a specified delay.
You'd call it like this:
$('yourElement').click(function (event) {
setTimeout(function () { console.log('hi'); }, 1000);
});
But I have to wonder why you need to do this. What's the problem you're trying to solve? Usually delaying stuff doesn't really solve anything.
jQuery's ajax functionality provides exactly what you are looking for. You can define a callback function to run after your ajax request.
Something like this:
$('#someElement').click(function(event){
event.preventDefault();
var loc = $(this).attr('href');
$.ajax({
url: "test.html",
complete: function(){
// Handle the complete event
loc = $(this).attr('href');
window.location.href = loc;
}
});
});
You may want to use ajaxStop instead of complete, it seems like your motivation for delaying navigation is because you have a bunch of asynchronous stuff going on and you want to make sure all your ajax stuff is complete before you navigate to that page.
Regardless I would recommend looking at http://api.jquery.com/Ajax_Events/ (a very useful page of documentation).

Is it possible that I can call another event handler inside an event?

I have these two set of codes, one is to prompt whenever the button is clicked,
$('.button_class').click(function(){
var baker_url = base_url + 'baker/baker/manage/Bread/1';
var answer = confirm('Are you sure?');
if(answer == true){
// if this is true, i will call an external script so that within this condition that process will be executed
}
else if(answer == false){
return false; // exits
}
});
and then this piece of code right here is the one responsible for executing the process when the button is clicked,
$('.another_button_class').click(function(e){
e.preventDefault();
var baker_url = base_url + 'baker/baker/manage/Bread/1';
var form = '#'+ $(this).attr('rel');
var url = $(form).attr('action');
var target = '#'+ $(form).attr('rel');
$(target).slideUp();
$.post(url, $(form).serialize(),function(data) {
$(target).html(data).slideDown(function(){
if(data == '<div class="ok">Added</div>'){
setTimeout(refresh,1000)
c();
window.location = baker_url; // sets the url after refreshing
}
});
});
});
in the first function, when answer == true, i want to execute the latter function (the one with the process execution when button is clicked).
Is it really possible that I can call an another function or event handler to execute its process inside another function?
Not sure if that is what you want
if(answer == true){
// if this is true, i will call an external script so that within this condition that process will be executed
$('.another_button_class').trigger('click');
}
This will trigger a call the click event handlers bound on the $('.another_button_class') element.
make sure to use e.preventDefault(); on the first click as well, or the link will be followed
If I understand the question correctly, you have an effect that needs to happen either when you click button #2 or when you click button #1 AND click yes in a prompt?
If so I can think of three options:
Name the second function and make it work if e is undefined; all it really does with it is prevent default. You could then call the named function from the first event.
Better version of 1: Make a new function that does everything except e.preventDefault(); in the second piece of code. You could then call this from both events.
Use jQuery to simulate a click event for the second button, if 'yes' is selected at the first one.
EDIT The second one would be preferable in this case. Use the third one if you actually need the event object for something.

Send information about clicked link to the server before redirect

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

Categories