Friday, October 20, 2006

Using Lightbox to prevent form double submit

Some month ago I wrote a javascript class that uses a slightly modified version of Lightbox to prevent users to click twice on a form submit button.
The idea is simple: just add a lightbox layer when a user clicks on a submit button and the game is done. This is not an elegant solution, but it works in many cases.
It works also with links that try to call form.submit() method: this class saves previously defined submit functions, creates the layer and then calls old function (if it exists).


var LightboxForm = Class.create();
LightboxForm.prototype = {

yPos : 0,
xPos : 0,

initialize: function(form) {
form = $(form);
form.oldsubmitdoublesubmit = form.submit;
form._lightbox_ = this;

Event.observe(form, 'submit', this.disableWithOverlay.bindAsEventListener(form), false);
form.submit = this.disableWithOverlayJS;
},

uninstall: function(form) {
form = $(form);
form.submit = form.oldsubmitdoublesubmit;
Event.stopObserving(form, 'submit', this.disableWithOverlay.bindAsEventListener(form), false);
},

disableWithOverlay: function(event) {
if(event.returnValue != false) {
this._lightbox_.activate();
return true;
} else {
return false;
}
},

disableWithOverlayJS: function(event) {
this._lightbox_.activate();
return this.oldsubmitdoublesubmit();
},

// Turn everything on - mainly the IE fixes
activate: function(){
if (browser == 'Internet Explorer'){
this.getScroll();
this.setScroll(0,0);
this.hideSelects('hidden');
}
this.displayLightbox("block");
},

// Ie requires height to 100% and overflow hidden or else you can scroll down past the lightbox
prepareIE: function(height, overflow){
bod = document.getElementsByTagName('body')[0];
bod.style.height = height;
bod.style.overflow = overflow;

htm = document.getElementsByTagName('html')[0];
htm.style.height = height;
htm.style.overflow = overflow;
},

// In IE, select elements hover on top of the lightbox
hideSelects: function(visibility){
selects = document.getElementsByTagName('select');
for(i = 0; i < visibility =" visibility;" ypos =" self.pageYOffset;" ypos =" document.documentElement.scrollTop;" ypos =" document.body.scrollTop;" display =" display;" display =" display;" browser ="="">


When the lightbox is activated a div called lightbox is displayed, so if you want provide some information to the user you can define a div using a function like this:



// Add in markup necessary to make this work. Basically two divs:
// Overlay holds the shadow
// Lightbox is the centered square that the content is put into.
addLightboxMarkup: function() {
bod = document.getElementsByTagName('body')[0];
overlay = document.createElement('div');
overlay.id = 'overlay';
bod.appendChild(overlay);

message = document.createElement('div');
message.id = 'lightbox';
message.className = 'leightbox';
message.innerHTML = 'Request sent, please wait...';
bod.appendChild(message);
}


Somewhere in your html page you should put something like:

new PreventDoubleSubmit();


Don't forget to use the right css file. You can get a copy here
You can download a copy of this javascript code here. In this file you will find also a class that provides an hook on onload window event to allow all forms in the current page to be wrapped by the LightboxForm object.

Update 1:
The script relies on prototype.js and uses a script to detect the browser (the script was made from Chris Campbell from ParticleTree).

Update 2: due to some error in this post, the script was not working. I apologies for this: this post was made too quickly in the past.
Now I made a little example on how to integrate the script in your pages. Just download this archive and see the index.html file. It should be quite easy to understand.


Update 3: Thanks to Ken B. I added a simple and nice feature to the script: customizable html message for the submit.
Actually the message showing during submit is controlled by this line: message.innerHTML = 'Request sent, please wait...';.

I changed the source code to let you pass a custom message to the PreventDoubleSubmit object.
So now you can write something like:
PreventDoubleSubmit('

Please wait...

');
. Of course, a default message is generated if you continue to use the old syntax.
I updated the script and the example.

22 Comments:

Anonymous Josh W said...

So I'm using ASP.NET and I included the JS file, implemented the CSS. I don't see anything happening. Any ideas?

December 13, 2006 9:05 PM  
Blogger Madchicken said...

Uhm...I think I missed to say that you have to put somewhere in your page a script like:

new PreventDoubleSubmit();

sorry for my fault.

December 14, 2006 10:22 AM  
Anonymous Anonymous said...

This is what I have been looking for, but I get a JS error about 'browser' not being defined. I'm I missing a file somewhere?

March 05, 2007 9:26 PM  
Blogger Madchicken said...

No...you're right: I missed the js for the browser detection. You can find it here. Add it to your page and you will be able to access to a global variable called browser.

March 06, 2007 8:59 AM  
Anonymous Ken B. said...

Hi. I was wondering if there was an easy way to pass in the message that gets displayed in the lightbox.

Thank you.

March 06, 2007 7:19 PM  
Anonymous kuschti said...

Hi madchicken

i want to use this script for a normal body onload.
everytime when the body loads must show the layer.

how i make this?

April 30, 2007 5:46 PM  
Blogger Madchicken said...

Hi, the script here is studied for forms and submitting.
For solving your problem, I think you should see how the Lightbox script works. Check out this: http://www.huddletogether.com/projects/lightbox/

Pierpaolo

April 30, 2007 6:32 PM  
Anonymous Anonymous said...

I've tried this script but it doesn't take into consideration any validation which may occur in the onsubmit() event.

Basically, I have a page where the onsubmit looks like this: onsubmit="return validateForm()". If the validation fails, the method returns false - which cancels the event.

When I add your script, this is the behavior:

1. validation method executes and shows an alert in case of bad data.

2. lightbox div appears and form is submitted anyway :-((

Is there a way you can modify your script to test if false was returned in the onsubmit?

May 16, 2007 11:52 AM  
Blogger Madchicken said...

I'll check the script, since it should do correctly what you're trying to obtain. In the meanwhile you can do your data validation using the onclick event of your form button instead of using the onsubmit method. Something like:

onclick="if(validateForm()) submit()"

This should do the right work.

May 16, 2007 12:00 PM  
Anonymous Anonymous said...

i would like to put this in many pages in my application without having to recode the onsubmit event on the onclick of each button.

if you try this html you will se that the submit happens every time, regardless of the false value being returned from the event:

(i had to replace <> chars with [] so that i could post to blog):

[html]
[head]
[link rel="stylesheet" href="lightbox.css" type="text/css" /]
[script type="text/javascript" src="prototype.js"][/script]
[script type="text/javascript" src="browserdetect.js"][/script]
[script type="text/javascript" src="preventdoublesubmit.js"][/script]

[script type="text/javascript"]
new PreventDoubleSubmit('[p]Please Wait...[/p]');

function validateForm() {
alert("validating form..");
return false;
}
[/script]
[/head]
[body]
[form method="post" action="unknown.html" onsubmit="return validateForm();"]

First Name: [input type="text" id="name"][br]
Last Name: [input type="text" id="surname"][br]
[input type="submit" value="Normal Submit"]
[input type="button" value="JS Submit" onclick="submit()"]

[/form]
[/body]
[/html]

May 16, 2007 3:09 PM  
Anonymous Anonymous said...

Ciao PierPaolo,

did you get a chance to try the html page I posted yesterday? are you getting the same result? the form is always posted, no matter what.

I tried putting an alert in the "disableWithOverlay" method, but it always says that "event.returnValue=undefined", even though i return false in the onsubmit event.

any ideas?

May 17, 2007 1:26 PM  
Blogger Madchicken said...

I looked at your example and seems that the order of the observers defined for the onsubmit event is reversed. I'm trying to solve the problem, but I'm a bit busy during these days. I'll post something new as soon as possible

May 17, 2007 2:53 PM  
Anonymous Tom said...

This script really rocks! Thanks for sharing.

I have a question, though. The script works totally fine in IE, but the message does not show in Firefox. That is, the overlay layer is shown, but no message box. Any ideas?

May 23, 2007 4:33 PM  
Blogger Madchicken said...

Uhm...that's really strange: here it is working right both on IE and FF. Are you sure to have installed the latest version?

May 23, 2007 4:50 PM  
Anonymous Tom said...

Thanks for you answer, Madchicken.

Well, I'm using the latest version (if http://madchicken.altervista.org/tech/download/preventdoublesubmit.js is the latest). Works in IE only.

I have two separate stylesheets (one IE and one non-IE). Could it be some conflicts?

May 23, 2007 6:46 PM  
Anonymous Tom said...

Aha, found the error. The message box shows up on top of the page, not in the center of the screen. Say that you have a form a bit down on the page, which forces you to scroll down, the message is somewhat out of bonds. I'll see if I can come up with a fix.

May 23, 2007 7:02 PM  
Anonymous Flux said...

Wonderful work! A couple of fixes:
In some cases onsubmit is null and that causes the lightbox to show even if there was asp.net client-side validation. Here is the fix:
disableWithOverlay: function(event) {
/* If nothing is attached to onsubmit the original would fail, so we shall first handle that case here */
if(!this.oldonsubmitdoublesubmit) {
this._lightbox_.activate();
return true;
}
.......
}

Also your example was using quirks mode because you did not have the full dtd url in the doctype. When not using quirks mode the overlay does not fill the screen properly in IE6 (fine in firefox, IE7, safari, etc). So I've added some fixes to the lightbox.css:

* html /* IE only */
{
overflow: hidden;
}
* html body /* IE only */
{
height: 100%;
width: 100%;

}

Thanks again!

March 14, 2008 4:39 PM  
Anonymous flux said...

Oops an update on my last note:
Get rid of the html overflow section and change the other section to this:
* html body /* IE only */
{
height: 100%;
width: 100%;
margin: auto;
}

That is working well for me now.

March 25, 2008 4:48 PM  
Blogger Madchicken said...

Thank you Flux. I updated the script and the css. I also updated the example in the zip file (and fixed and error in the index.html too)

April 23, 2008 9:51 AM  
Anonymous Brandon said...

Hello: (love this script)

Replacing <> with [] so it will show up

ok, I need this lightbox to launch after form validation and I cannot seem to get it to work.. it ignores the function that launches the lightbox.

Here is what I have:

[script language="JavaScript" type="text/javascript"]
[!--
function checkform ( form )
{
// see http://www.thesitewizard.com/archive/validation.shtml
// for an explanation of this script and how to use it on your
// own website

// ** START **
if (form.name_first.value == "") {
alert( "Please enter your First Name." );
form.name_first.focus();
valid = "false";
return false ;
}
// ** END **
return true;

}
//--]

[/script]

If I put your code into the // ** END ** section it won't run the lightbox (it will just submit my form) and I think it has to do with the function using the external .js file preventdoublesubmit.js
example:

}
// ** END **
new PreventDoubleSubmit('[center][img src="loading.gif" align="absbottom"]    Please Wait...[/center]');
}

If I use this code outside of the form validation function everything works fine except it runs even if they get an alert to check a form field, which is not good, I only want it to run your script if everything is true and the form is ready for processing.
example:
[script type="text/javascript"]
new PreventDoubleSubmit('[center][img src="loading.gif" align="absbottom"]    Please Wait...[/center]');
[/script]

any help would be stellar,
Thanks,
Brandon

April 24, 2008 7:59 PM  
Blogger Madchicken said...

Hi Brandon, please take a look at the zip example.
The zip contains a simple page that's very similar to your code.
Please, contact me at pfollia at gmail dot com if you can't get it work.

April 25, 2008 12:49 PM  
Anonymous Brandon said...

Thanks for the help! I now have it working. I forgot that your example already had form validation.. I should have checked :) hindsight is always 20/20.

Take care,
Brandon

April 25, 2008 7:40 PM  

Post a Comment

Links to this post:

Create a Link

<< Home