I have a cancel button, that does an ajax and then refreshes page contents, and when navigating away I want to trigger the button, but I don't want it to refresh anything in the UI.
I thought of using a global variable, placed in the window object, but that does not seem very nice:
$(".cancel").bind("click", function(e) {
e.preventDefault();
tellTheServerThatUserCanceled(); // ajax call
if (!isUnloading) refreshUI();
});
$(window).bind("unload", function(e) {
isUnloading = true; // this is disgusting, I don't want to do this
$(".cancel").trigger("click");
}
Is there any official way, or another more elegant way, or I shouldn't be worried about using global variables?
EDIT:
The unload event code does not know what exactly it must do, because the page can have multiple edit panels, with multiple cancel buttons. All it knows is that it must trigger the cancel buttons of each panel.
I find its nicer not to run your code in jQuery's anonymous functions, but rather have them call functions that are sharable. Something like this illustrates the general idea:
function doCancel(e, isUnloading){
e.preventDefault();
tellTheServerThatUserCanceled(); // ajax call
if (!isUnloading) refreshUI();
}
$(".cancel").bind("click", function(e) {
doCancel(e, false);
});
$(window).bind("unload", function(e) {
doCancel(e, true);
}
Related
I have an C#.NET MVC3 web app and I have a question related to the attached Stackoverflow question. I am using a window.beforeunload event to see if there have been changes made on my View. If so, I alert the user that they have unsaved changes. However, if they selected the Create (submit) button, the dialog alerting the user still pops up. I want to NOT pop up the dialog if the Create button is selected. Any ideas? Is there a way to see which control was clicked?
I can think of 2 solutions:
$('#submitBtn').click(function() {
unbindOnBeforeUnload();
});
// OR
// maybe you have multiple cases where you don't want this triggered,
// so this will be better
var shouldTriggerOnBeforeUnload = true;
$('#submitBtn').click(function() {
shouldTriggerOnBeforeUnload = false;
});
...
$(document).unload(function() {
if (shouldTriggerOnBeforeUnload) {
confirm();
}
});
I've written it in a jQuery-like syntax, but only to keep the code concise, you can adapt it to anything you want.
We have many hyperlinks in a html page. On click of which we do certain function.
After one hyperlink is clicked I wanted to make other hyperlink clicks to do nothing until first one finishes it processing. (During testing testers started clicking the hyperlinks rapidly one after another)
I did something like this, but it does not seem to be working. Basically used a variable to track if a hyperlink is clicked.
var hyperlinkClickInProcess=false;
function clickHandler(inputData){
if(hyperlinkClickInProcess ==false){
hyperlinkClickInProcess =true;
linkProcessing(inputData);
hyperlinkClickInProcess =false;
}
}
Any thoughts on how to implement such functionality?
function disableAllLinks() {
// search for all links and remove onclick event handlers, + return false.
}
function enableAllLinks() {
// search for all links and reassing onclick event handlers
}
function clickHandler(inputData){
disableAllLinks();
/// Link processing body here ////
enableAllLinks();
}
This question tells how to use jquery to disable all the links on a page: jQuery disable a link. But instead of disabling just one specific link, you could use a similar strategy on all the links on the page by doing like so:
$('a').click(function(e) {
if(hyperlinkClickInProcess) {
e.preventDefault();
}
else {
hyperlinkClickInProcess =true;
linkProcessing(inputData);
hyperlinkClickInProcess =false;
}
});
I am popping up a dialog box when someone tries to navigate away from a particular page without having saved their work. I use Javascript's onbeforeunload event, works great.
Now I want to run some Javascript code when the user clicks "Cancel" on the dialog that comes up (saying they don't want to navigate away from the page).
Is this possible? I'm using jQuery as well, so is there maybe an event like beforeunloadcancel I can bind to?
UPDATE: The idea is to actually save and direct users to a different webpage if they chose cancel
You can do it like this:
$(function() {
$(window).bind('beforeunload', function() {
setTimeout(function() {
setTimeout(function() {
$(document.body).css('background-color', 'red');
}, 1000);
},1);
return 'are you sure';
});
});
The code within the first setTimeout method has a delay of 1ms. This is just to add the function into the UI queue. Since setTimeout runs asynchronously the Javascript interpreter will continue by directly calling the return statement, which in turn triggers the browsers modal dialog. This will block the UI queue and the code from the first setTimeout is not executed, until the modal is closed. If the user pressed cancel, it will trigger another setTimeout which fires in about one second. If the user confirmed with ok, the user will redirect and the second setTimeout is never fired.
example: http://www.jsfiddle.net/NdyGJ/2/
I know this question is old now, but in case anyone is still having issues with this, I have found a solution that seems to work for me,
Basically the unload event is fired after the beforeunload event. We can use this to cancel a timeout created in the beforeunload event, modifying jAndy's answer:
$(function() {
var beforeUnloadTimeout = 0 ;
$(window).bind('beforeunload', function() {
console.log('beforeunload');
beforeUnloadTimeout = setTimeout(function() {
console.log('settimeout function');
$(document.body).css('background-color', 'red');
},500);
return 'are you sure';
});
$(window).bind('unload', function() {
console.log('unload');
if(typeof beforeUnloadTimeout !=='undefined' && beforeUnloadTimeout != 0)
clearTimeout(beforeUnloadTimeout);
});
});
EDIT: jsfiddle here
Not possible. Maybe someone will prove me wrong... What code do you want to run? Do you want to auto-save when they click cancel? That sounds counter-intuitive. If you don't already auto-save, I think it makes little sense to auto-save when they hit "Cancel". Maybe you could highlight the save button in your onbeforeunload handler so the user sees what they need to do before navigating away.
I didn't think it was possible, but just tried this idea and it works (although it is some what of a hack and may not work the same in all browsers):
window.onbeforeunload = function () {
$('body').mousemove(checkunload);
return "Sure thing";
};
function checkunload() {
$('body').unbind("mousemove");
//ADD CODE TO RUN IF CANCEL WAS CLICKED
}
Another variation
The first setTimeout waits for the user to respond to the browser's Leave/Cancel popup. The second setTimeout waits 1 second, and then CancelSelected is only called if the user cancels. Otherwise the page is unloaded and the setTimeout is lost.
window.onbeforeunload = function(e) {
e.returnValue = "message to user";
setTimeout(function () { setTimeout(CancelSelected, 1000); }, 100);
}
function CancelSelected() {
alert("User selected stay/cancel");
}
window.onbeforeunload = function() {
if (confirm('Do you want to navigate away from this page?')) {
alert('Saving work...(OK clicked)')
} else {
alert('Saving work...(canceled clicked)')
return false
}
}
with this code also if user clicks on 'Cancel' in IE8 the default navigation dialog will appear.
I'm using buttons to submit data via Ajax. I'm using jQuery to disable and enable the buttons. This is to prevent "button-mashing," where a user can fire multiple requests either maliciously or unwittingly.
Is there an "element-agnostic" way to prevent this behavior in jQuery? For example, say I wanted to use anchors instead of buttons to submit the data. A button I can disable; but as far as I know you can not disable anchors.
Here is how I'm doing this now: (note I've removed some of the unnecessary code to make it shorter)
$('.fav .button').click(function() {
$.ajax({
context: this,
dataType: 'json',
beforeSend: function() {
// Toggle state; disable button to prevent button mashing
$(".fav").toggleClass("fav-state-1");
$(".fav .button").attr("disabled", true);
},
error: function() {
// Rollback state and re-enable button on error
$(".fav").toggleClass("fav-state-1");
$(".fav .button").attr("disabled", false);
},
success: function(response) {
if (response.result == "success") {
$(".fav .button").attr("disabled", false);
}
else {
// Rollback state; re-enable button
$(".fav").toggleClass("fav-state-1");
$(".fav .button").attr("disabled", false);
}
}
});
return false;
});
HTML:
<input class="button" type="button" value="">
Of course, the best way to do this would be to handle it gracefully on the server side.
That said, you could use the data storage methods in jQuery to store a value to indicate it has already been clicked, and use that to determine if the user has already clicked/pressed the button. The values get stored per selector, so you can set it on anything.
$("a").click(function(e) {
e.preventDefault();
if (!$(this).data('isClicked')) {
var link = $(this);
// Your code on successful click
// Set the isClicked value and set a timer to reset in 3s
link.data('isClicked', true);
setTimeout(function() {
link.removeData('isClicked')
}, 3000);
} else {
// Anything you want to say 'Bad user!'
}
});
The benefit is that you're not stopping the user from clicking anything else, as it's a per element solution. In your case, you might want to do the link.removeData in the success function.
Example of it working: http://jsfiddle.net/jonathon/ke8Az/ (Note that if you try to click again within the 3s, you get the 'Please wait' but you can still click the rest)
Note: This is a client side solution only. And only if they have JavaScript installed. Unless you handle it on the server side, the user can maliciously send multiple requests. This just helps with the 'unwittingly' part.
Before the ajax call you could unbind the click event on the clicked object, then in the success / error method you could rebind the click event.
That way they can mash the button as much as they want but it wont have the click wired up until the call has finished.
You could do the following:
setup a variable clickedWithinLastSecond.
in the method that fires the request, check if it is true, if it is then don't send the request
If it is not send the request and set the variable to true. Setup a method that fires after a second with setTimeout that changes the variable back to false.
you will have to customize variable name to your needs, and you will need to find a way to keep the variable in the correct scopes, but that is not difficult.
The best and only way to stop the behavior you are describing is on the server side.
You can also use debounce to register only one click. Both underscore.js and lodash.js provide this handy method.
Here's a fiddle to demo the concept. With lazyClick, you can double/triple click on the link yet the event handler is fired only once.
var lazyClick = _.debounce(onclickHandler, 500);
function onclickHandler(e){
e.preventDefault();
console.log('clicked');
}
$(function(){
// uncomment this and you will see double clicks are being registered.
//$('#btn').click(onclickHandler);
// with debounce, only one click will be registered
$('#btn').click(lazyClick);
});
I have a page with a form that is submittes via ajaxSubmit() (so, without changing the page).
My goal is that, when the user try to change page (or even to close the browser), i ask him if really want to exit the page without sending the form (exactly as gmail does).
Gmail for example do this with a window.confirm-like popup, but if it is possible, i'll like to handle it with custom messages and options.
jQuery have the unload event:
$(window).unload( function () { alert("Bye now!"); } );
but it permits me just to do something before exit the page; i need to 'block' the page exit, if the user click the relative button.
So, how to handle (and cancel) the page-exit event?
try the following. Demo here
<script type="text/javascript">
function unloadPage(){
return "dont leave me this way";
}
window.onbeforeunload = unloadPage;
</script>
It's possible bind the "onbeforeunload" event with jQuery:
$(window).bind('beforeunload', function(e) {
return "ATTENZIONE!!";
});
It works!!