Choosing to Continue or Not Continue after Clicking on Link - javascript

I am attempting to do something pretty simple: click on a link, modal pops up to continue or cancel to the link's URL, continue to the URL or cancel (essentially hide the modal). My issue is the "waiting" period when the modal pops up, when the user is prompted to continue or cancel. Right now, my code never seems to run past the first waitForModalEvent() call:
<a href="someURL" onclick='return handleClick()'> Click Here </a>
function handleClick() {
if (dataChanged()) {
returnValue = false;
displayModal();
returnValue = waitForModalEvent();
//never called at or past this point. Tested with alert()
return returnValue;
} else {
return true;
}
}
var continueClicked = false;
var cancelClicked = false;
function waitForModalEvent() {
while(!continueClicked && !cancelClicked) {
waitForModalEvent(); //I know this gives the browser some troubles
}
if (continueClicked) {
return true;
} else {
return false;
}
}
I know this code is faulty (especially the hideous waitForModalEvent() recursive call that never ends). However, I'm stuck at how to resolve this, and return true or false in handleClick() after the user clicks on either continue or cancel. Is my setup using the <a href>'s onclick inherently a bad setup for what I'm trying to accomplish?
I've read up on callbacks, but can't grasp how I could use callbacks for my situation (if any). Would appreciate any sort of suggestions or insight!

You've generated an infinite loop which locks up the JavaScript event loop. Until the while loop finished the variables you are testing in it can never changed.
If you want to do something based on a DOM based dialogue, you have to do it with callbacks. There is no way (outside of a host environment provided function like confirm) to block while waiting for a user interaction.
The general approach to using callbacks here would be to always cancel the default action of clicking the link, and then have the callback replicate its functionality (or just put a regular link in the dialogue).

Check this codepen for an illustration of callbacks and modal dialogues with jQuery UI:
http://codepen.io/anon/pen/KdaRmP
$('button.showModal').click(function() {
$( "#dialog-confirm" ).dialog({
resizable: false,
modal: true,
buttons: {
"Proceed to The Dividing Line": function() {
$( this ).dialog( "close" );
location.href='http://www.thedividingline.com/';
},
Cancel: function() {
$('DIV.output').text('Canceled.');
$( this ).dialog( "close" );
}
}
});
});
I used an example from jQuery UI docs here: https://jqueryui.com/dialog/#modal-confirmation (some things I needed to change).
EDIT
Now callback invokes a hyperlink.

Related

JQuery / dirty forms / window.onbeforeunload only triggered after link selection

I'm trying to implement a warning for the users in case they are leaving the form without saving.
The warning dialog works as expected but with the only exception that when the user chooses to 'Stay on Page', the selected side menu entry changed to the one the user clicked on (form is the same).
How can I make sure that the same menu item is still selected once the user chooses to 'Stay on Page'?
var warnMessage = "Unsaved changes. Do you really want to leave the page?";
$(document).ready(function () {
$('a.k-link').on('click', function () {
window.onbeforeunload = function () {
if (isDirty) return warnMessage;
}
});
});
You might find it easier (and possibly more consistent across browsers) to use a confirm prompt (remember, it's a blocking dialog).
<script>
var warnMessage = "Unsaved changes. Do you really want to leave the page?";
$('a.k-link').on('click', function (e) {
if (isDirty && !confirm(warnMessage)) {
e.preventDefault();
}
});
</script>
There are at least two reasons to avoid onbeforeunload:
The spec doesn't require a browser to display the message you
provide, and not all browsers do, and
the correct event is actually beforeunload
You can and should handle this event through window.addEventListener() and the beforeunload event. More documentation is available there. (MDN)
I'm just guessing, since the Kendo UI scripts aren't exactly fun to read through, but the 'selected' class is getting applied because a navigation event was started, even though you cancel it; the Kendo script is probably just listening for a successful click. onbeforeunload and beforeunload both happen after the click event has resolved (AFAIK, anyway).
Following worked for me (adding e.stopPropagation):
$('a.k-link').on('click', function (e) {
if (isDirty && !confirm(warnMessage)) {
e.preventDefault();
e.stopPropagation();
} });
or by returning false:
$('a.k-link').on('click', function (e) {
if (isDirty && !confirm(warnMessage)) {
return false;
} });

Detect page unload with javascript

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);
}

disable button in a <li>

okay, if I have six buttons in a list, under the li tag (each on is rel to a part of an array), how can I disable a button while it's doing it's thing? (In this case playing a video)I know it's a little vague (i haven't supplied code or anything of the sort), but that's because I don't know how to go about it. If I could at least get pointed in the right direction, that would be helpful, so that even if I can't figure it out, at least I can be specific with my problem... thanks...EDIT this is what I've now done
<li rel='1' id="first">
<div style="top:0px;">
<img src="graphics/filler.png" alt="" width="280" height="128" onClick="asess"/>
</div>
</li>
and then added the corresponding function
function asess() {
document.getElementById("first").disabled = true;
}
I'm not to concerned with adding the function back just yet, because first I'd like to make this part work.EDIT I've got this, which should work, but I guess it's not "talking" to the button?
$("li, .thumbs").bind("touchstart click", function() {
var $this = $(this);
if (!document.getElementById("first").disabled) {
document.getElementById("first").disabled = true }
else {document.getElementById("first").disabled = false};
});
I know it will only talk to the button with that id (first one) but as long as I can make it work for one, I can do the rest. So, what am I doing wrong?
Each button will have an onclick event handler. To prevent the onclick handler from doing anything the JavaScript method attached to the handler should return false. If you are doing this with jQuery return false; is the same as calling e.preventDefault (or event.preventDefault for IE).
When the normal event handler initiates the action associated with the button it should add the event handler that disables the onclick action.
You will probably need to apply a new CSS style to the button as well so the user knows it's disabled.
When the action completes you need to remove event handler that disables the onclick action and use the normal one again.
You could always just use a flag to say an action is in progress and set this on and off with the actions. If the flag is on then the event handler method returns false.
By using the event handler you could also show an alert to the user when they try and click the button before you return false.
EDIT:
Here is the sort of JavaScript you'll need, the first click starts the process which will stop itself after five seconds using setTimeout('stopAction()', 5000);. If you click the item again during that time you get the wait message.
I would recommend you look at using jQuery to develop a robust cross browser solution.
var inProgress = false;
function asess() {
if(inProgress) {
alert('Please wait ...');
return false;
} else {
startAction();
}
}
function startAction() {
inProgress = true;
alert('Starting');
document.getElementById("first").style.backgroundColor = '#333333';
setTimeout('stopAction()', 5000);
}
function stopAction() {
inProgress = false;
alert('Stopping');
document.getElementById("first").style.backgroundColor = '#FFFFFF';
}
document.getElementById("my_button").disabled = true;
and when you're done.
document.getElementById("my_button").disabled = false;
You could "disable" the element within the click handler and re-enable it when the callback is executed successfully.
Click handler binding to elements with disabled="disabled" attribute is not guaranteed to be consistently implemented across browsers (i.e. the event could/would still fire) and is not allowed except on form elements anyway. I'd just add class="disabled" which gives me additional powers to style the disabled element state by, say, greying it out.
Oh, and jQuery. Naturally, this logic could be reproduced in "normal" javascript but is so tidier with library usage, fiddle:
$('#my-button').click(function() {
var $this = $(this); //cache the reference
if (!$this.hasClass('disabled')) {
$this.addClass('disabled');
alert('hello world!');
setTimeout(function($btn) {
$btn.removeClass('disabled');
}, 5000, $this);
} else {
return false;
}
});

jQuery modal dialog does not stop for user input

I am new to jQuery but have already implemented successfully several modal dialogs using the jqueryUI dialog widget. In trying to implement another one, the modal dialog opens, but the code continues on to execute without stopping for user input. Using jQuery 1.7.1 and jquery-ui-1.8.16.
Here is the definition of a "prototype" of the dialog (it is a "prototype" because it doesn't take the actions on the "OK" selection that would be needed to meet requirements):
var $confirm = $('#confirm');
$confirm.dialog(
{
autoOpen:false,
width:440,
modal:true,
buttons:
{
OK: function()
{
$( this ).dialog( 'close' );
},
Cancel: function()
{
$( this ).dialog( 'close' );
}
}
});
Here is some test code that opens the dialog:
[ some javascript that does error checking]
alert('stop1');
$('#confirm').dialog('open');
alert('stop2');
[ more javascript including submitting the form]
What happens is the the first alert displays. Upon clicking on it the dialog opens along with the second alert, indicating that the dialog is not waiting for user input. The second alert is modal and prevents the dialog from being accessed. When it is clicked on, the form submits. This sequence shows that the dialog is not waiting for user input.
I have looked and looked at my other successfully implemented modal dialogs and do not see what might be causing this one to fail.
The dialog won't wait. Instead you'll want to use this as a point to decide what you want to happen. So instead of including additional code that you may or may not want to run after the dialog modal, let that be the last part of the function.
Then, with your OK or Cancel functions, make the call there to continue on with the workflow if they chose ok, or just hide and do whatever cancel stuff needs to be done with the cancel.
In short, the modal dialog will not pause execution of the javascript, it will just run the code to open the modal and keep on going.
You should use a promise:
function deferredConfirm(message) {
$('<div></div>').html(message).dialog({
dialogClass: 'confirmDialog',
buttons:
[{
text: buttonText,
click: function () {
$(this).dialog("close");
defer.resolve();
}
},
{
text: buttonText2,
click: function () {
$(this).dialog("close");
defer.reject();
}
}],
close: function () {
$(this).remove();
}
});
return defer.promise();
}
And to call it:
deferredConfirm("Oh No!").then(function() {
//do something if dialog confirmed
});

Way to know if user clicked Cancel on a Javascript onbeforeunload Dialog?

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.

Categories

Resources