Prevent page from exiting - javascript

I've made a function to give a warning when a user navigates away when a certain form field is populated:
window.addEventListener("beforeunload", function (event) {
var unsaved = "Are you sure you want to exit?";
var text = $('.article_div textarea').val();
if (text.length > 0){
event.returnValue = unsaved;
return unsaved;
}
});
This actually works perfectly. However, I looked up returnValue and it is recommended to not use it. I have tried alternatives including removing event.returnValue = unsaved; and just using return unsaved. However, that also doesn't work - it still navigates away from the page.
Any ideas as to what I can do to make it work?

If you use jQuery, event.returnValue can be omitted. See here.
$(window).on('beforeunload', function(event) {
var unsaved = "Are you sure you want to exit?";
var text = 'Test Text ###';
//var text = $('.article_div textarea').val();
if (text.length > 0){
return unsaved;
}
});
See example here.

Related

Jquery, onBlur - if not empty show an alert

I'm trying to modify some other code that I found on SO, but it's not working (I'm still learning JQ)
My code:
$("#Email").blur(function(){
var inp = $("#Email").val();
if(jQuery.trim(inp).length > 0)
{
alert("Yay!");
}
} );
Basically (in case it's not clear) I want to fire that alert() as the user moves away from the textbox - only if the user entered something in the textbox.
Code seems to work, make sure the field is loaded before binding the event, preferably using $(document).ready()
$(document).ready(function(){
$("#Email").blur(function(){
var inp = $("#Email").val();
if(jQuery.trim(inp).length > 0)
{
alert("Yay!");
}
} );
})
Here is the related fiddle

iPhone Javascript Confirm Dialog Bug

I have a javascript confirm dialog popping up, but when I tap 'Cancel', then after the dialog closes, tap anywhere on the screen, the dialog pops up again. It only happens the one extra time, then you can tap on the page again without the dialog popping up.
I'm only seeing this on iPhone/iPad running iOS 5.0.1. I don't have an iOS 6 device, so I'm not sure it's happening there.
Here's the code I'm using:
$(bpm.remoteAppDivName).on('tap', 'a.delete-pending-payment', function(event) {
if (isJQMGhostClick(event)) { return false; }
var deleteGlobalPaymentURL = $(this).attr('href');
var confirmMsg = confirm ("Are you sure you want to do that?");
if (confirmMsg === true){
window.location = '/index.htm';
}
event.preventDefault();
return false;
});
var lastclickpoint, curclickpoint;
var isJQMGhostClick = function(event){
curclickpoint = event.clientX+'x'+event.clientY;
var ret=false;
if (lastclickpoint === curclickpoint) {
ret=true;
} else {
ret=false;
}
lastclickpoint = curclickpoint;
return ret;
}
Here's a link to the problem page: http://www.5280skateparks.com/dev/confirmBug.htm
Any help would be extremely appreciated.
UPDATE: I just confirmed that it's happening on iOS 6.0.1 as well.
This is the jQuery Mobile "Ghost Click" discussed in some detail here and here. On the forum page, a solution was proposed, which I have reproduced below with a small bug fix:
var lastclickpoint, curclickpoint;
var isJQMGhostClick = function(event){
curclickpoint = event.clientX+'x'+event.clientY;
var ret=false;
if (lastclickpoint === curclickpoint) {
ret=true;
} else {
ret=false;
}
lastclickpoint = curclickpoint;
return ret;
}
I have modified this code slightly to not always expect a pair of clicks. This function now works correctly in the case of 0 ghost clicks and more than 2 ghost clicks. You can use it by checking isJQMGhostClick(event) at the beginning of your tap handler and ignoring the event if the isJQMGhostClick function returns true.

Understanding event bubbling in Javascript

I've been trying to understand even bubbling, and not quite sure I completely follow it. I started reading about it so that I could warn users when they were leaving a page on my website if they had started to enter data into a form (in a similar way to Stack Overflow does!).
The following code seems to work cross-browser:
var entereddata = false;
$(document).ready(function()
{
$('#contactform').bind('keypress',function(e) {
if((e.which > 96 && e.which < 123) || (e.which > 47 && e.which < 58)) {
entereddata = true;
//alert(e.which);
}
});
});
function confirmLeave(e, d)
{
if(!e) e = window.event;//window.event;
if(!d) d = entereddata;
var confirmationMessage = 'It appears you have started to enter information into the contact form, but have not yet submitted it';
if(!d)
{
e.cancelBubble = true;
} else
{
return confirmationMessage;
}
}
window.onbeforeunload=confirmLeave;
However, this also gets called when I click the submit button for the form, which I don't want. I've tried various additions to the code, such as adding:
if($('#submit').click()){
submitted=true;
} else {
submitted=false;
}
and then changing if(!d) to if(!d && submitted==false) to the main code; however, this (and every other combination of trying to get the page to fire only if the submit button isn't clicked) doesn't work, with the warning either still showing when I click the submit button, or no warning being shown when anything is clicked!
This might boil down to the fact I don't understand the event bubbling process - I don't know why I need the e.cancelBubble = true; in the place I have it.
So, my two main problems are:
how do I check if the submit button is clicked, and only show the warning if it isn't clicked
and to understand eventBubbling; for example: if enteredData is true, then I'm not affecting the bubbling process. Should I be? Should I have e.cancelBubble=false if enteredData is false and e.cancelBubble=true if enteredData is true? What effect does setting the value of e.cancelBubble actually have when closing a page?
Am I also correct in thinking I don't need the event e.stopPropagation
at all, because Firefox supports event bubbling?
What about having such code?
$('#submit').click(function() {
entereddata = false;
});
This should be called before the actual form submission i.e. before confirmLeave is running, so lowering the flag should do the trick.
Try removing the onbeforeunload "listener":
$('#submit').click(function() {
window.onbeforeunload=null;
});
I don't think you need to worry about bubbling in this example...
return null if you want the browser to move on without asking the user, or return a string if you want the browser to show an alert asking the user if he wants to move on or not...
function confirmLeave(e) {
e = e || window.event;//window.event;
var confirmationMessage = 'It appears you have started to enter information into the contact form, but have not yet submitted it';
if(entereddata) {
return confirmationMessage;
} else {
return null;
}
}
Bubbling and propagation only applies to event's that should notify it's children or it's parents, and as far as i know window.onbeforeunload is a global event that will not be propagated.
Unrelated to bubbling, but you could bypass detecting whether keys were pressed and check the form data instead:
function hasNonemptyTextInputs() {
var textInputs = $('#contactform :input').filter(':text, textarea');
// Check for any field with a nonempty value
// .is() returns true iff the function returns true on any element
return textInputs.is(function() {
return $(this).val().length > 0;
});
}

Problem with event.target in IE

I'm writing js for a status update system to be used on various pages throughout a app that I'm working. I am really just starting to get more comfortable with javascript so it has been somewhat of a challenge to get to the point where I have everything now.
The status system is basically a facebook clone. For the most part everything is supposed to function the way that facebook's status updates and status comments do. The intended behavior is that when the user clicks in the status textarea, the div under the status textarea slides out revealing the submit button as well as some other checkboxes.
If the user clicks anywhere else on the page except a link or any element that has the class prevent_slideup the div slides up hiding the submit button and any checkboxes.
I'm using a document.body click function to determine what the user clicked on so I know which form elements to hide if I should even hide them. I do not want this slideup to take place on a textarea if that textarea has focus or the user is selecting a checkbox that goes with that form. Hence the prevent_slideup class. I also do not want to bother running the slideup logic if the user has clicked on a link. I'd prefer they just leave the page without having to wait for the animation.
The code that I was using to accomplish this task can be found in the $(document.body).click(function (e) section below where I'm doing a .is('a') check on the event target.
This code works as expected in chrome and firefox, however in ie when a link is clicked for the first time it seems that the element stored in var target is actually a div instead of an anchor. What ends up happening is that the submit div slides up and the user is not taken to the link that they just clicked on. If a link is clicked a second time the user is taken to the page as you would expect.
It seems to me that there's some kind of a lag in ie as to what the current event being fired is.
The entire status module is working other than this one strange ie bug regarding the users click on the link not being carried out the first time that they click a link after opening the status textarea. Does anything jump out in this script that would explain this behavior or does anyone have any other advice?
Thanks in advance for your help.
$(document).ready(function(){
$("textarea.autoresize").autoResize();
});
$(document.body).click(function (e){
var target = e.target || e.srcElement;
console.log(target);
console.log($(target).is('a'));
if($(target).hasClass('prevent_slideup') || $(target).is('a'))
{
return true;
}
else
{
var active_element = document.activeElement;
var active_status_id = $(active_element).attr('data-status_id');
var active_has_data_status_id = (typeof active_status_id !== 'undefined' && active_status_id !== false) ? true : false;
$('textarea').each(function(){
if($(this).hasClass('status_comment_textarea'))
{
var status_id = $(this).attr('data-status_id');
if($('#comment_textarea_'+status_id).val() === '' && (!active_has_data_status_id || active_status_id !== status_id))
{
hide_status_comment_submit(status_id);
}
}
else if($(this).attr('id') === 'status_textarea')
{
if($('#status_textarea').val() === '' && $(active_element).attr('id') !== 'status_textarea')
{
$('#status_textarea').html($("#status_textarea").attr('placeholder'));
hide_status_submit();
}
}
});
return true;
}
});
$("#status_textarea").live('click', function(){
if($('#status_textarea').val() === $("#status_textarea").attr('placeholder'))
{
$('#status_textarea').html('');
}
show_status_submit();
return false;
});
$(".comment_toggle").live('click', function(){
var status_id = $(this).attr('data-status_id');
show_status_comment_submit(status_id);
return false;
});
$(".status_comment_submit").live('click', function(){
var status_id = $(this).attr('data-status_id');
$('#status_comment_submit_wrapper_'+status_id).addClass('status_comment_submit_successful');
return false;
});
$(".show_hidden_comments").live('click', function(){
var status_id = $(this).attr('data-status_id');
$('#status_hidden_comments_'+status_id).show();
$(this).hide();
return false;
});
function hide_status_submit()
{
$("#status_textarea").removeAttr('style');
$("#status_textarea").blur();
$("#status_block").removeClass('padding_b10');
$("#status_submit_wrapper").slideUp("fast");
return false;
}
function show_status_submit()
{
if ($("#status_submit_wrapper").is(":hidden"))
{
$("#status_block").addClass('padding_b10');
$("#status_submit_wrapper").slideDown('fast');
}
return false;
}
function hide_status_comment_submit(status_id)
{
if(!$('#status_comment_submit_wrapper_'+status_id).is(":hidden"))
{
$('#status_comment_submit_wrapper_'+status_id).hide();
$('#fake_comment_input_'+status_id).show();
$('#comment_textarea_'+status_id).removeAttr('style');
}
return false;
}
function show_status_comment_submit(status_id)
{
if($('#status_comment_submit_wrapper_'+status_id).is(":hidden"))
{
$('#fake_comment_input_'+status_id).hide();
$('#status_comment_submit_wrapper_'+status_id).show();
$('#comment_textarea_'+status_id).focus();
}
return false;
}
function status_comment_submit_successful()
{
hide_status_comment_submit($('.status_comment_submit_successful').attr('data-status_id'));
$('.status_comment_submit_successful').removeClass('status_comment_submit_successful');
return false;
}
I figured out that there were two main issues with my script...
1.) The document.body function and the #status_textarea live click funtioins were conflicting with each other.
2.) After adding the logic for the #status_textarea function into the document.body function I noticed that the script still didn't quite work as expected in internet explorer unless I had an alert in the function. The problem at this point was that the autoresize plugin that I'm using on the textarea was also conflicting with the document.body function.
I was able to rectify the situation by adding a dummy text input and hiding the status textarea. On click of the dummy text input the status textarea is shown and the the dummy text input is hidden. I have no idea why this worked, but it seems to have solved my problems.

How do I warn a user before closing a page when textarea is not empty?

I'm trying to replicate the same thing as on the stackoverflow textareas.
EDIT: I went with something like this, after reading the suggestions here:
window.onbeforeunload = function()
{
var myTextArea = document.getElementById('post_content');
if (myTextArea.value.length > 0)
{
return "You haven\'t submitted your post; are you sure you want to discard it?";
}
}
This seemed to work with Firefox and other browsers without causing double confirmations.
Use something like:
window.onunload = function(){
var myTextArea = [a ref to your textarea];
if (myTextArea.value.length > 0) {
//=>textarea contains text, ask the user:
return confirm('You didn\'t submit your text yet! Are you sure'+
' you want to navigate away from this page?');
}
//=>continue unloading
return true;
}

Categories