Link to home
Start Free TrialLog in
Avatar of brianadkins
brianadkinsFlag for United States of America

asked on

Using Javascript to validate email address on shopping cart checkout form

I'm working with a Yahoo online store cart which currently requires that the user enter an email address.  Unfortunately, Yahoo provides zero validation for the email field.

Ideally, I would like to have two email input fields and then check to see if they are identical.  However, all the cart code is generated by the server and I have no way of doing this on the server side...  However, I AM able to add some custom Javascript and CSS to the page which may be of benefit.

I've posted a very simplified version of the cart html below...

Here's what I was thinking might be possible:

1. Define an additional email field and use Javascript and CSS to position it near the 'real' one
2. Use Javascript to check to see if the two values are the same
3. When the values are NOT identical, show a red warning mesage next to the field
4. User would never be prevented from proceeding... even if values are different

Is something like this possible with Javascript?

(I am a lot more experienced with the server-side stuff like php and mysql... but Javascript has always seemed a bit like voodoo to me!)

I'll split the points up between the most helpful answers, even if they are in a different direction than my idea above.
<html>
  <FORM name="CheckoutForm" method="post" action="yadayadayada">
    <INPUT type="text" class="text" name="various.other.address.fields" id="xyz">
    ...
    <INPUT type="text" class="text" name="miscDS.shopperEmailAddress" id="billing-email">
    ....
</FORM>
</html>

Open in new window

Avatar of MMDeveloper
MMDeveloper
Flag of United States of America image

sure this will be simple, let me write something up real quick.
Avatar of hielo
>>1. Define an additional email field and use Javascript and CSS to position it near the 'real' one
Why the additional field?
try:

<html>
<script>
function validate(f){
 var ok=true;
 
 if(f['real-email'].value == '' && f['billing-email'].value=='' )
 {
  document.getElementById('emailMsg').innerHTML="Email is a required field";
  ok=false;
 }
 else 
 if( f['real-email'].value != f['billing-email'].value ){
  document.getElementById('emailMsg').innerHTML="Email addresses do not match";
  ok=false;
 }
 else if( !/\b[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i.test(f['real-email'].value) )
 {
  document.getElementById('emailMsg').innerHTML="Invalid email address";
  ok=false;
 }
return ok;
}
</script>
  <FORM name="CheckoutForm" method="post" action="yadayadayada" onsubmit="return validate(this)">
    <INPUT type="text" class="text" name="various.other.address.fields" id="xyz">
    ... 
    <INPUT type="text" class="text" name="miscDS.shopperEmailAddress" id="real-email">
    <INPUT type="text" class="text" name="miscDS.shopperEmailAddress" id="billing-email"><span id="emailMsg" style="background-color:beige;border:3px double orange;"></span>
    ....
    <input type="submit"/>
</FORM>
</html>

Open in new window

you may need to edit the validateForm() function to reference the actual ID's of the email fields but here is an untested solution. just call the validateForm() function on submit (or attach it as an onclick of the submit button). The function will auto-submit the form on success.

If either of the email fields are invalid, it will apply a red background color to it, give focus to the field, and select the text within it.
function isValidEmailAddr(str) {
 
	var at = "@";
	var dot = ".";
	var lat = str.indexOf(at);
	var lstr = str.length;
	var ldot = str.indexOf(dot);
	if (str.indexOf(at) == -1){
	   return false;
	}
 
	if (str.indexOf(at) == -1 || str.indexOf(at) == 0 || str.indexOf(at) == lstr){
	   return false;
	}
 
	if (str.indexOf(dot) == -1 || str.indexOf(dot) == 0 || str.indexOf(dot) == lstr){
	    return false;
	}
 
	 if (str.indexOf(at,(lat+1)) != -1){
	    return false;
	 }
 
	 if (str.substring(lat-1,lat) == dot || str.substring(lat+1,lat+2) == dot){
	    return false;
	 }
 
	 if (str.indexOf(dot,(lat+2)) == -1){
	    return false;
	 }
	
	 if (str.indexOf(" ") != -1){
	    return false;
	 }
 
	 return true;
}
 
function validateForm() {
	theForm = document.getElementsByName("CheckoutForm")[0];
	email1 = document.getElementById("billing-email"); //main email field
	email2 = document.getElementById("xyz"); //confirm email field
	
	if (isValidEmailAddr(email1.value)) {
		if (email2.value == email1.value) {
			//success
			theForm.submit();
		}
		else {
			//confirm email doesn't match valid main email field
			grabTBAttention(email2);
		}
	}
	else {
		//main field invalid email
		grabTBAttention(email1);
	}
}
 
function grabTBAttention(el) {
	try {
		el.style.backgroundColor = "#FF0000";
		el.focus();
		el.select();
	}
	catch(e) {
		//suppress error
	}
	return false;
}

Open in new window

Avatar of brianadkins

ASKER

Good stuff so far....  I'll need some time to test them out, but here's some more info in the mean time:

1. I'm not really a fan of validating the format of email addresses to make sure the are *@*.* because most of the problems we see are the result of mis-spellings and not getting the format wrong.  An example would be customer types in abcdfe@aol.com instead of abcdef@aol.com  or maybe they even type abc@aol.cmo

2. Having two fields that must be identical is the best way to reduce mis-typing in my opinion (but feel free to set me straight !)
With respect to Hielo's response... that looks like what I was thinking... but unfortunately, I don't have the ability to add the extra input and span tags into the code.  I can only add a bit of code into either the header or the footer of the page.

Is there a way to write something that will generate those two tags which will position them on the page using CSS so that they appear next to the original email field?
>>I don't have the ability to add the extra input and span tags into the code.
OK, then is email field contained within it's own span or div?

<html>
<script>
function validate(f){
 var ok=true;
 
 if(!document.getElementById("emailMsg"))
 {
	f['real-email'].parentNode.innerHTML = f['real-email'].parentNode.innerHTML + '<span id="emailMsg" style="background-color:beige;border:3px double orange;">Email is a required field</span>'; 	
 }
 
 if(f['real-email'].value == '' && f['billing-email'].value=='' )
 {
  document.getElementById('emailMsg').innerHTML="Email is a required field";
  ok=false;
 }
 else if( f['real-email'].value != f['billing-email'].value ){
  document.getElementById('emailMsg').innerHTML="Email addresses do not match";
  ok=false;
 }
 else if( !/\b[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i.test(f['real-email'].value) )
 {
  document.getElementById('emailMsg').innerHTML="Invalid email address";
  ok=false;
 }
return ok;
}
</script>
  <FORM name="CheckoutForm" method="post" action="yadayadayada" onsubmit="return validate(this)">
    <INPUT type="text" class="text" name="various.other.address.fields" id="xyz">
    ...
 
    <div><INPUT type="text" class="text" name="miscDS.shopperEmailAddress" id="real-email"></div>
    <div><INPUT type="text" class="text" name="miscDS.shopperEmailAddress" id="billing-email"></div>
    ....
    <input type="submit"/>
</FORM>
</html>

Open in new window

yes!

I've pasted the DIV below which contains three inputs...  however, we are already using CSS to NOT display the second and third inputs (id's labelconfirm-email and labelratings.

... so, effectively, that DIV tag only contains one input field that ends up being displayed on the page.



<H4 class="ys_subSectionHeader" state="">Email Notification</H4> 
<DIV class="ys_subSection" id="ys_billingEmail" style=""> 
 
<FIELDSET> 
 
<LABEL for="billing-email" id="labelbilling-email" class="text"> 
<STRONG>Email Address:</STRONG> 
<INPUT type="text" class="text" name="miscDS.shopperEmailAddress" id="billing-email" size="40" maxlength="99" value=""> 
<INPUT type="hidden" name="miscDS.shopperEmailAddress_ymixval" value="req,email"> 
<INPUT type="hidden" name="miscDS.shopperEmailAddress_ymixlabel" value="Email Address"> 
<INPUT type="hidden" name="miscDS.shopperEmailAddress_secname" value="BillingEmail"> 
</LABEL> 
 
<LABEL for="confirm-email" id="labelconfirm-email" class="checkbox "> 
<INPUT type="hidden" id="miscDS.sendConfirmEmail_CKVAL" name="miscDS.sendConfirmEmail" value="1"> 
<INPUT type="checkbox" class="checkbox" name="miscDS.sendConfirmEmail_CKBOX" id="confirm-email" value="1" onclick="javascript:if (this.checked) {document.getElementById(&#39;miscDS.sendConfirmEmail_CKVAL&#39;).value=&#39;1&#39;;} else {document.getElementById(&#39;miscDS.sendConfirmEmail_CKVAL&#39;).value=&#39;0&#39;;}" checked="checked"> 
</LABEL> 
 
<LABEL for="ratings" id="labelratings" class="checkbox "> 
<INPUT type="hidden" id="miscDS.ratingsEnabled_CKVAL" name="miscDS.ratingsEnabled" value="1"> 
<INPUT type="checkbox" class="checkbox" name="miscDS.ratingsEnabled_CKBOX" id="ratings" value="1" onclick="javascript:if (this.checked) {document.getElementById(&#39;miscDS.ratingsEnabled_CKVAL&#39;).value=&#39;1&#39;;} else {document.getElementById(&#39;miscDS.ratingsEnabled_CKVAL&#39;).value=&#39;0&#39;;}"> 
<STRONG>Would you like Yahoo! to send you an email asking you to rate this merchant?</STRONG> 
</LABEL> 
 
</FIELDSET> 
 
</DIV> 

Open in new window


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 "http://www.w3.org/TR/html4/loose.dtd">
 
<html>
<head>
<title></title>
<style type="text/css">
<!--
.eMsg{background-color:beige;border:3px double orange;}
-->
</style>
 
<script>
function validate(f){
 var ok=true;
 var eAddress=document.getElementById("billing-email");
 if(!document.getElementById("emailMsg"))
 {
 	var s = document.createElement("span");
	s.id="emailMsg";
	s.className="eMsg";
	eAddress.parentNode.insertBefore(s,eAddress.nextSibling)
 }
 
 if(eAddress.value == ''  )
 {
  document.getElementById('emailMsg').innerHTML="Email is a required field";
  ok=false;
 }
 /*
 else if( f['real-email'].value != f['billing-email'].value ){
  document.getElementById('emailMsg').innerHTML="Email addresses do not match";
  ok=false;
 }
 */
 else if( !/\b[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i.test(eAddress.value) )
 {
  document.getElementById('emailMsg').innerHTML="Invalid email address";
  ok=false;
 }
 else if( document.getElementById("confirm-email").checked===false) 
 {
  document.getElementById('emailMsg').innerHTML="You must confirm your email address.";
  ok=false;
 }
return ok;
}
</script>
</head>
<body>
<form onsubmit="return validate(this);">
<H4 class="ys_subSectionHeader" state="">Email Notification</H4> 
<DIV class="ys_subSection" id="ys_billingEmail" style=""> 
 
<FIELDSET> 
 
<LABEL for="billing-email" id="labelbilling-email" class="text"> 
<STRONG>Email Address:</STRONG> 
<INPUT type="text" class="text" name="miscDS.shopperEmailAddress" id="billing-email" size="40" maxlength="99" value=""> 
<INPUT type="hidden" name="miscDS.shopperEmailAddress_ymixval" value="req,email"> 
<INPUT type="hidden" name="miscDS.shopperEmailAddress_ymixlabel" value="Email Address"> 
<INPUT type="hidden" name="miscDS.shopperEmailAddress_secname" value="BillingEmail"> 
</LABEL> 
 
<LABEL for="confirm-email" id="labelconfirm-email" class="checkbox "> 
<INPUT type="hidden" id="miscDS.sendConfirmEmail_CKVAL" name="miscDS.sendConfirmEmail" value="1"> 
<INPUT type="checkbox" class="checkbox" name="miscDS.sendConfirmEmail_CKBOX" id="confirm-email" value="1" onclick="javascript:if (this.checked) {document.getElementById(&#39;miscDS.sendConfirmEmail_CKVAL&#39;).value=&#39;1&#39;;} else {document.getElementById(&#39;miscDS.sendConfirmEmail_CKVAL&#39;).value=&#39;0&#39;;}" checked="checked"> 
</LABEL> 
 
<LABEL for="ratings" id="labelratings" class="checkbox "> 
<INPUT type="hidden" id="miscDS.ratingsEnabled_CKVAL" name="miscDS.ratingsEnabled" value="1"> 
<INPUT type="checkbox" class="checkbox" name="miscDS.ratingsEnabled_CKBOX" id="ratings" value="1" onclick="javascript:if (this.checked) {document.getElementById(&#39;miscDS.ratingsEnabled_CKVAL&#39;).value=&#39;1&#39;;} else {document.getElementById(&#39;miscDS.ratingsEnabled_CKVAL&#39;).value=&#39;0&#39;;}"> 
<STRONG>Would you like Yahoo! to send you an email asking you to rate this merchant?</STRONG> 
</LABEL> 
 
</FIELDSET> 
 
</DIV> 
 
<input type="submit" value="Submit"/>
</form>
</body>
</html>

Open in new window

Heilo,
Trying your latest solution, but only one email field shows when the page loads

Also, to reduce confusion, I've re-pasted the html code below and omitted the two fields that we don't use (both are checkboxes) and that are not invloved in this scenario
<H4 class="ys_subSectionHeader" state="">Email Notification</H4> 
<DIV class="ys_subSection" id="ys_billingEmail" style=""> 
 
<FIELDSET> 
 
<LABEL for="billing-email" id="labelbilling-email" class="text"> 
<STRONG>Email Address:</STRONG> 
<INPUT type="text" class="text" name="miscDS.shopperEmailAddress" id="billing-email" size="40" maxlength="99" value=""> 
<INPUT type="hidden" name="miscDS.shopperEmailAddress_ymixval" value="req,email"> 
<INPUT type="hidden" name="miscDS.shopperEmailAddress_ymixlabel" value="Email Address"> 
<INPUT type="hidden" name="miscDS.shopperEmailAddress_secname" value="BillingEmail"> 
</LABEL> 
 
</FIELDSET> 
 
</DIV> 

Open in new window

>>but only one email field shows when the page loads
Well what you pasted has only one email text field. I don't know what you are talking about. On the last code I posted I assumed that checking the checkbox was your way of "verifying" the email.
I wish we had the ability to add a second email field immediately after the first by changing something on the server, but we don't... the input fields are set in stone and we are only allowed to tweak them using javascript and CSS.

In other words, I am unable to directly change the contents of that DIV tag (id="ys_billingEmail").  All I am allowed to do is insert code at the very bottom or top of the page that modifies the contents of that DIV tag via javascript or CSS...

... I was hoping to make that a little more clear, but I may have failed miserably...
>>I wish we had the ability to add a second email field immediately after the first by changing something on the server, but we don't...
OK, so you want to add that field dynamically as well?
try:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
 "http://www.w3.org/TR/html4/loose.dtd">
 
<html>
<head>
<title></title>
<style type="text/css">
<!--
.eMsg{background-color:beige;border:3px double orange;}
-->
</style>
 
<script>
window.onload=init;
function init()
{
 var eAddress=document.getElementById("billing-email");
 if(!document.getElementById("emailMsg"))
 {
 	var s = document.createElement("span");
	s.id="emailMsg";
	s.className="eMsg";
	eAddress.parentNode.insertBefore(s,eAddress.nextSibling);
	var d = document.createElement("div");
	d.innerHTML="<strong>Verify Email address: </strong><input type='text' name='vEmail' value='' id='vEmail' />";
	eAddress.parentNode.insertBefore(d,s.nextSibling);
 }
}
 
function validate(f){
 var ok=true;
 var eAddress=document.getElementById("billing-email");
 
 if(eAddress.value == ''  )
 {
  document.getElementById('emailMsg').innerHTML="Email is a required field";
  ok=false;
 }
 
 else if( eAddress.value != document.getElementById("vEmail").value.value ){
  document.getElementById('emailMsg').innerHTML="Email addresses do not match";
  ok=false;
 }
 
 else if( !/\b[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b/i.test(eAddress.value) )
 {
  document.getElementById('emailMsg').innerHTML="Invalid email address";
  ok=false;
 }
 
 else if( document.getElementById("confirm-email").checked===false) 
 {
  document.getElementById('emailMsg').innerHTML="You must confirm your email address.";
  ok=false;
 }
 
return ok;
}
</script>
</head>
<body>
<form onsubmit="return validate(this);">
<H4 class="ys_subSectionHeader" state="">Email Notification</H4> 
<DIV class="ys_subSection" id="ys_billingEmail" style=""> 
 
<FIELDSET> 
 
<LABEL for="billing-email" id="labelbilling-email" class="text"> 
<STRONG>Email Address:</STRONG> 
<INPUT type="text" class="text" name="miscDS.shopperEmailAddress" id="billing-email" size="40" maxlength="99" value=""> 
<INPUT type="hidden" name="miscDS.shopperEmailAddress_ymixval" value="req,email"> 
<INPUT type="hidden" name="miscDS.shopperEmailAddress_ymixlabel" value="Email Address"> 
<INPUT type="hidden" name="miscDS.shopperEmailAddress_secname" value="BillingEmail"> 
</LABEL> 
 
<LABEL for="confirm-email" id="labelconfirm-email" class="checkbox "> 
<INPUT type="hidden" id="miscDS.sendConfirmEmail_CKVAL" name="miscDS.sendConfirmEmail" value="1"> 
<INPUT type="checkbox" class="checkbox" name="miscDS.sendConfirmEmail_CKBOX" id="confirm-email" value="1" onclick="javascript:if (this.checked) {document.getElementById(&#39;miscDS.sendConfirmEmail_CKVAL&#39;).value=&#39;1&#39;;} else {document.getElementById(&#39;miscDS.sendConfirmEmail_CKVAL&#39;).value=&#39;0&#39;;}" checked="checked"> 
</LABEL> 
 
<LABEL for="ratings" id="labelratings" class="checkbox "> 
<INPUT type="hidden" id="miscDS.ratingsEnabled_CKVAL" name="miscDS.ratingsEnabled" value="1"> 
<INPUT type="checkbox" class="checkbox" name="miscDS.ratingsEnabled_CKBOX" id="ratings" value="1" onclick="javascript:if (this.checked) {document.getElementById(&#39;miscDS.ratingsEnabled_CKVAL&#39;).value=&#39;1&#39;;} else {document.getElementById(&#39;miscDS.ratingsEnabled_CKVAL&#39;).value=&#39;0&#39;;}"> 
<STRONG>Would you like Yahoo! to send you an email asking you to rate this merchant?</STRONG> 
</LABEL> 
 
</FIELDSET> 
 
</DIV> 
 
<input type="submit" value="Submit"/>
</form>
</body>
</html>

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of hielo
hielo
Flag of Wallis and Futuna image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Bingo! ...  

Two last things....  

1. Can the fields be checked when the user 'leaves' the second field instead of when the for is submitted?

2. Also, Whenever I clicked in the second (dynamically generated) field, the focus immediately snapped back to the first field (had a hard time entering the email the second time)
>> Can the fields be checked when the user 'leaves' the second field instead of when the for is submitted?
Then put an onchange event handler on the dynamic field (the verify email field) and call your function from there.

>>Whenever I clicked in the second (dynamically generated) field,
you mean whenever you clicked on the label (as opposed to the actual field). Try:
	d.innerHTML="<label for='vEmail' style='font-weight:bold;'>Verify Email address: </label><input type='text' name='vEmail' value='' id='vEmail' />";

Open in new window

Points are in the mail..... thanks!
you are welcome