Solved

making form fields required depending upon toggle state

Posted on 2006-11-08
13
643 Views
Last Modified: 2012-08-14
Hi all,

I have a form which is being validated using the Yaromat script:

function YY_checkform() { //v4.71
//copyright (c)1998,2002 Yaromat.com
  var a=YY_checkform.arguments,oo=true,v='',s='',err=false,r,o,at,o1,t,i,j,ma,rx,cd,cm,cy,dte,at;
  for (i=1; i<a.length;i=i+4){
    if (a[i+1].charAt(0)=='#'){r=true; a[i+1]=a[i+1].substring(1);}else{r=false}
    o=MM_findObj(a[i].replace(/\[\d+\]/ig,""));
    o1=MM_findObj(a[i+1].replace(/\[\d+\]/ig,""));
    v=o.value;t=a[i+2];
    if (o.type=='text'||o.type=='password'||o.type=='hidden'){
      if (r&&v.length==0){err=true}
      if (v.length>0)
      if (t==1){ //fromto
        ma=a[i+1].split('_');if(isNaN(v)||v<ma[0]/1||v > ma[1]/1){err=true}
      } else if (t==2){
        rx=new RegExp("^[\\w\.=-]+@[\\w\\.-]+\\.[a-zA-Z]{2,4}$");if(!rx.test(v))err=true;
      } else if (t==3){ // date
        ma=a[i+1].split("#");at=v.match(ma[0]);
        if(at){
          cd=(at[ma[1]])?at[ma[1]]:1;cm=at[ma[2]]-1;cy=at[ma[3]];
          dte=new Date(cy,cm,cd);
          if(dte.getFullYear()!=cy||dte.getDate()!=cd||dte.getMonth()!=cm){err=true};
        }else{err=true}
      } else if (t==4){ // time
        ma=a[i+1].split("#");at=v.match(ma[0]);if(!at){err=true}
      } else if (t==5){ // check this 2
            if(o1.length)o1=o1[a[i+1].replace(/(.*\[)|(\].*)/ig,"")];
            if(!o1.checked){err=true}
      } else if (t==6){ // the same
            if(v!=MM_findObj(a[i+1]).value){err=true}
      }
    } else
    if (!o.type&&o.length>0&&o[0].type=='radio'){
          at = a[i].match(/(.*)\[(\d+)\].*/i);
          o2=(o.length>1)?o[at[2]]:o;
      if (t==1&&o2&&o2.checked&&o1&&o1.value.length/1==0){err=true}
      if (t==2){
        oo=false;
        for(j=0;j<o.length;j++){oo=oo||o[j].checked}
        if(!oo){s+='* '+a[i+3]+'\n'}
      }
    } else if (o.type=='checkbox'){
      if((t==1&&o.checked==false)||(t==2&&o.checked&&o1&&o1.value.length/1==0)){err=true}
    } else if (o.type=='select-one'||o.type=='select-multiple'){
      if(t==1&&o.selectedIndex/1==0){err=true}
    }else if (o.type=='textarea'){
      if(v.length<a[i+1]){err=true}
    }
    if (err){s+='* '+a[i+3]+'\n'; err=false}
  }
  if (s!=''){alert('The required information is incomplete or contains errors:\t\t\t\t\t\n\n'+s)}
  document.MM_returnValue = (s=='');
}
function toggle(){
     var list = document.forms[0].deliverytype;
     if(list.options[list.selectedIndex].value == "email_delivery"){
          document.getElementById("email_delivery").style.display = "block";
          document.getElementById("postal_delivery").style.display = "none";
          }else{
     if(list.options[list.selectedIndex].value == "postal_delivery"){
          document.getElementById("postal_delivery").style.display = "block";
          document.getElementById("email_delivery").style.display = "none";
          }
     }
}

As you can see, there is a toggle function tacked on (my doing) which is being used to show/hide elements depending upon a select menu:

            <select name="deliverytype" onChange="toggle()">
                  <option></option>
        <option value="email_delivery">Email</option>
        <option value="postal_delivery">Postal Mail</option>
            </select>
  <p id="email_delivery"> <span class="bold">Recipient's Email:</span>
    <input name="product[]" type="text" id="RecipientEmail" />
</p>
  <div id="postal_delivery">
  <p><b>Delivery Address:</b>
    <input name="product[]" type="text" id="PostalDeliveryAddress" />
    </p>
        <p><b>Delivery City:</b>
    <input name="product[]" type="text" id="PostalDeliveryCity" />
    </p>
        <p><b>Delivery State/Province:</b> ...etc.

So far, so good, works great...I want to make the fields associated with each toggled state required depending on what is selected...so for instance, if "Email" is selected, I want to require that "RecipientEmail" is filled out once it becomes visible...and vice versa.

Is there a way that I can accomplish this and not have the fields associated with the other toggle state always be required even if they are not visible?

thanks,

H

0
Comment
Question by:headbump
  • 7
  • 6
13 Comments
 
LVL 6

Expert Comment

by:sodalitas
Comment Utility
Not familiar with this code, a couple things come to mind but can you explain what the contents of   var a=YY_checkform.arguments looks like?  It appears to contain 4 pieces of information per control that is to be validated, where is this declared, can you add another piece of information?  So then your loop would increment i by 5 instead of 4, and you could have the name of the div tag that contains the element be the last piece of information.  Then you can add a check to see that if (a[5] < "" ) then check that document.getElementById(a[5]).style.display == "none" then skip it
0
 

Author Comment

by:headbump
Comment Utility
S,

Here is the function call:

<form action="xx" method="post" name="form1" id="form1" onsubmit="YY_checkform('form1','RecipientName','#q','0','Please enter the Recipient\'s Name.','SenderName','#q','0','Please enter Your Name.','SenderEmail','#S','2','Please enter a valid email address in the Your Email field.','deliverytype','#q','1','You must select a Delivery Type.');return document.MM_returnValue">

The rest of what you mentioned went right over my head...hence the post :)

thanks,

H
0
 
LVL 6

Expert Comment

by:sodalitas
Comment Utility
The function breaks the arguments into pieces by incrementing the value of i by 4 as it goes through the list like this:

'RecipientName','#q','0','Please enter the Recipient\'s Name.'
'SenderName','#q','0','Please enter Your Name.'
'SenderEmail','#S','2','Please enter a valid email address in the Your Email field.'
'deliverytype','#q','1','You must select a Delivery Type.'

The loop then finds the control named a[i] (for instance, 'RecipientName'), checks the type of validation to do with a[i+1] and a[i+2] based on the type of control you are validating, then if there's a problem it uses a[1+3] as the error message.

So I would suggest send a new parameter in the list of arguments like this

<form action="xx" method="post" name="form1" id="form1" onsubmit="YY_checkform('form1','RecipientName','#q','0','Please enter the Recipient\'s Name.','', 'SenderName','#q','0','Please enter Your Name.','', 'SenderEmail','#S','2','Please enter a valid email address in the Your Email field.', 'email_delivery', 'deliverytype','#q','1','You must select a Delivery Type.', '');return document.MM_returnValue">

In the example above you're not sending data on the other fields, but basically I added a parameter after the error message for each control, with blank in most cases and 'email_delivery' for the SenderEmail control.

Now in your code, replace
  for (i=1; i<a.length;i=i+4){
with
  for (i=1; i<a.length;i=i+5){

at this point, if you do a test you'll see nothing has changed, except you are now passing in the data for each control corresponding to the div that that control should be in.  So now you can add this code right after the for loop

if ((a[5] < "") &&(document.getElementById(a[5]).style.display == "none")) {
   continue;
} else {

And add another closing bracket at the end of the function
}

This should only do the validation for that control if it isn't in a div tag that's currently hidden.

An alternative to this is to create a function that will create your argument list and have it only create the argument list for the currently visible controls.  Let me know if you want to know about this option.
0
 
LVL 6

Expert Comment

by:sodalitas
Comment Utility
Sorry, thats a[i+4], not a[5]
0
 

Author Comment

by:headbump
Comment Utility
S,

Before I try this, since I want to validate RecipientEmail and not SenderEmail again, should I add that to the list like this:

<form action="xx" method="post" name="form1" id="form1" onsubmit="YY_checkform('form1','RecipientName','#q','0','Please enter the Recipient\'s Name.','', 'SenderName','#q','0','Please enter Your Name.','', 'SenderEmail','#S',",'Please enter a valid email address in the Your Email field.', 'email_delivery', 'deliverytype','#q','1','You must select a Delivery Type.', 'RecipientEmail','#S','2','Please enter a valid email address in the Recipient Email field.''');return document.MM_returnValue">

?

thx,

H
0
 
LVL 6

Expert Comment

by:sodalitas
Comment Utility
If SenderEmail is not in the hidden div but RecipientEmail is, you would do this:

<form action="xx" method="post" name="form1" id="form1" onsubmit="YY_checkform('form1','RecipientName','#q','0','Please enter the Recipient\'s Name.','', 'SenderName','#q','0','Please enter Your Name.','', 'SenderEmail','#S',",'Please enter a valid email address in the Your Email field.', '', 'deliverytype','#q','1','You must select a Delivery Type.', '', 'RecipientEmail','#S','2','Please enter a valid email address in the Recipient Email field.', 'email_delivery');return document.MM_returnValue">

So all fields have an additional [, ''] after it and RecipientEmail, since it's in the div called email_delivery, has a [, 'email_delivery'] after it
0
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 

Author Comment

by:headbump
Comment Utility
S,

This does work when the div is shown, but the validation is also happening when the div is hidden and when the form is submitted with no delivery type chosen...upon all submissions really (which makes sense I guess because the validation is occurring onsubmit...

thx,

H
0
 
LVL 6

Expert Comment

by:sodalitas
Comment Utility
Me and my stupid syntax again.  

Should be

if ((a[i+4] > "") &&(document.getElementById(a[i+4]).style.display == "none")) {

Note the > instead of <

If that doesn't work, throw some alert() messages in there to see what the value of those are.
0
 

Author Comment

by:headbump
Comment Utility
Hmm,
Now it's throwing up one alert per control being checked...one right after the other...
here's the script again, perhaps I have something screwy?

<script language="JavaScript" type="text/JavaScript">
<!--
function MM_findObj(n, d) { //v4.01
  var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
    d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
  if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
  for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
  if(!x && d.getElementById) x=d.getElementById(n); return x;
}

function YY_checkform() { //v4.71
//copyright (c)1998,2002 Yaromat.com
  var a=YY_checkform.arguments,oo=true,v='',s='',err=false,r,o,at,o1,t,i,j,ma,rx,cd,cm,cy,dte,at;
  //for (i=1; i<a.length;i=i+4){
   for (i=1; i<a.length;i=i+5){
   if ((a[i+4] > "") &&(document.getElementById(a[i+4]).style.display == "none")) {
   continue;
} else {
    if (a[i+1].charAt(0)=='#'){r=true; a[i+1]=a[i+1].substring(1);}else{r=false}
    o=MM_findObj(a[i].replace(/\[\d+\]/ig,""));
    o1=MM_findObj(a[i+1].replace(/\[\d+\]/ig,""));
    v=o.value;t=a[i+2];
    if (o.type=='text'||o.type=='password'||o.type=='hidden'){
      if (r&&v.length==0){err=true}
      if (v.length>0)
      if (t==1){ //fromto
        ma=a[i+1].split('_');if(isNaN(v)||v<ma[0]/1||v > ma[1]/1){err=true}
      } else if (t==2){
        rx=new RegExp("^[\\w\.=-]+@[\\w\\.-]+\\.[a-zA-Z]{2,4}$");if(!rx.test(v))err=true;
      } else if (t==3){ // date
        ma=a[i+1].split("#");at=v.match(ma[0]);
        if(at){
          cd=(at[ma[1]])?at[ma[1]]:1;cm=at[ma[2]]-1;cy=at[ma[3]];
          dte=new Date(cy,cm,cd);
          if(dte.getFullYear()!=cy||dte.getDate()!=cd||dte.getMonth()!=cm){err=true};
        }else{err=true}
      } else if (t==4){ // time
        ma=a[i+1].split("#");at=v.match(ma[0]);if(!at){err=true}
      } else if (t==5){ // check this 2
            if(o1.length)o1=o1[a[i+1].replace(/(.*\[)|(\].*)/ig,"")];
            if(!o1.checked){err=true}
      } else if (t==6){ // the same
            if(v!=MM_findObj(a[i+1]).value){err=true}
      }
    } else
    if (!o.type&&o.length>0&&o[0].type=='radio'){
          at = a[i].match(/(.*)\[(\d+)\].*/i);
          o2=(o.length>1)?o[at[2]]:o;
      if (t==1&&o2&&o2.checked&&o1&&o1.value.length/1==0){err=true}
      if (t==2){
        oo=false;
        for(j=0;j<o.length;j++){oo=oo||o[j].checked}
        if(!oo){s+='* '+a[i+3]+'\n'}
      }
    } else if (o.type=='checkbox'){
      if((t==1&&o.checked==false)||(t==2&&o.checked&&o1&&o1.value.length/1==0)){err=true}
    } else if (o.type=='select-one'||o.type=='select-multiple'){
      if(t==1&&o.selectedIndex/1==0){err=true}
    }else if (o.type=='textarea'){
      if(v.length<a[i+1]){err=true}
    }
    if (err){s+='* '+a[i+3]+'\n'; err=false}
  }
  if (s!=''){alert('The required information is incomplete or contains errors:\t\t\t\t\t\n\n'+s)}
  document.MM_returnValue = (s=='');
}
}

function toggle(){
     var list = document.forms[0].deliverytype;
     if(list.options[list.selectedIndex].value == "email_delivery"){
          document.getElementById("email_delivery").style.display = "block";
          document.getElementById("postal_delivery").style.display = "none";
          }else{
     if(list.options[list.selectedIndex].value == "postal_delivery"){
          document.getElementById("postal_delivery").style.display = "block";
          document.getElementById("email_delivery").style.display = "none";
          }
     }
}
//-->
</script>

thx,

H
0
 
LVL 6

Expert Comment

by:sodalitas
Comment Utility
Ok I plugged in parts of your code above into a sample html page and this seems to work:

<html>
<head></head>
<body>
<script language="JavaScript" type="text/JavaScript">
<!--
function MM_findObj(n, d) { //v4.01
  var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
    d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
  if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
  for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
  if(!x && d.getElementById) x=d.getElementById(n); return x;
}

function YY_checkform() { //v4.71
//copyright (c)1998,2002 Yaromat.com
  var a=YY_checkform.arguments,oo=true,v='',s='',err=false,r,o,at,o1,t,i,j,ma,rx,cd,cm,cy,dte,at;
  //for (i=1; i<a.length;i=i+4){
   for (i=1; i<a.length;i=i+5){
   if ((a[i+4] > "") &&(document.getElementById(a[i+4]).style.display == "none")) {
   continue;
} else {
    if (a[i+1].charAt(0)=='#'){r=true; a[i+1]=a[i+1].substring(1);}else{r=false}
    o=MM_findObj(a[i].replace(/\[\d+\]/ig,""));
    o1=MM_findObj(a[i+1].replace(/\[\d+\]/ig,""));
    v=o.value;t=a[i+2];
    if (o.type=='text'||o.type=='password'||o.type=='hidden'){
      if (r&&v.length==0){err=true}
      if (v.length>0)
      if (t==1){ //fromto
        ma=a[i+1].split('_');if(isNaN(v)||v<ma[0]/1||v > ma[1]/1){err=true}
      } else if (t==2){
        rx=new RegExp("^[\\w\.=-]+@[\\w\\.-]+\\.[a-zA-Z]{2,4}$");if(!rx.test(v))err=true;
      } else if (t==3){ // date
        ma=a[i+1].split("#");at=v.match(ma[0]);
        if(at){
          cd=(at[ma[1]])?at[ma[1]]:1;cm=at[ma[2]]-1;cy=at[ma[3]];
          dte=new Date(cy,cm,cd);
          if(dte.getFullYear()!=cy||dte.getDate()!=cd||dte.getMonth()!=cm){err=true};
        }else{err=true}
      } else if (t==4){ // time
        ma=a[i+1].split("#");at=v.match(ma[0]);if(!at){err=true}
      } else if (t==5){ // check this 2
            if(o1.length)o1=o1[a[i+1].replace(/(.*\[)|(\].*)/ig,"")];
            if(!o1.checked){err=true}
      } else if (t==6){ // the same
            if(v!=MM_findObj(a[i+1]).value){err=true}
      }
    } else
    if (!o.type&&o.length>0&&o[0].type=='radio'){
          at = a[i].match(/(.*)\[(\d+)\].*/i);
          o2=(o.length>1)?o[at[2]]:o;
      if (t==1&&o2&&o2.checked&&o1&&o1.value.length/1==0){err=true}
      if (t==2){
        oo=false;
        for(j=0;j<o.length;j++){oo=oo||o[j].checked}
        if(!oo){s+='* '+a[i+3]+'\n'}
      }
    } else if (o.type=='checkbox'){
      if((t==1&&o.checked==false)||(t==2&&o.checked&&o1&&o1.value.length/1==0)){err=true}
    } else if (o.type=='select-one'||o.type=='select-multiple'){
      if(t==1&&o.selectedIndex/1==0){err=true}
    }else if (o.type=='textarea'){
      if(v.length<a[i+1]){err=true}
    }
    if (err){s+='* '+a[i+3]+'\n'; err=false}
  }
  if (s!=''){alert('The required information is incomplete or contains errors:\t\t\t\t\t\n\n'+s)}
  document.MM_returnValue = (s=='');
}
}

function toggle(){
     var list = document.forms[0].deliverytype;
     if(list.options[list.selectedIndex].value == "email_delivery"){
          document.getElementById("email_delivery").style.display = "block";
          document.getElementById("postal_delivery").style.display = "none";
          }else{
     if(list.options[list.selectedIndex].value == "postal_delivery"){
          document.getElementById("postal_delivery").style.display = "block";
          document.getElementById("email_delivery").style.display = "none";
          }
     }
}

var MM_returnValue;

//-->
</script>

<form action="xx" method="post" name="form1" id="form1"

onsubmit="YY_checkform('form1','RecipientEmail','#S','2','Please enter a valid email address in the

Recipient Email field.', 'email_delivery');return document.MM_returnValue">

Recipient Name: <input type=text id="RecipientName" /><BR>
Sender Name: <input type=text id="SenderName" /><BR>
Sender Email: <input type=text id="SenderEmail" /><BR>


<select name="deliverytype" onChange="toggle()">
        <option value="email_delivery">Email</option>
        <option value="postal_delivery">Postal Mail</option>
</select>

<p id="email_delivery"> <span class="bold">Recipient's Email:</span>
    <input name="product[]" type="text" id="RecipientEmail" />
</p>

<div id="postal_delivery">
  <p><b>Delivery Address:</b>
    <input name="product[]" type="text" id="PostalDeliveryAddress" />
    </p>
       <p><b>Delivery City:</b>
    <input name="product[]" type="text" id="PostalDeliveryCity" />
    </p>
</div>

<input type=Submit value="Submit" />

</form>

</body>
</html>

If I pick email_delivery and don't put anything in the Recipient email field the validation shows, but if I pick postal_delivery it does not show.  Compare this code above to what you are doing.  See any differences?
0
 

Author Comment

by:headbump
Comment Utility
S,

First, thanks for all your help...now what's happening is that the error for recipient's email is firing after the one for delivery type not being chosen...the validation works when the delivery type is chosen for email, but it also fires when the deliverytype field validation is set off.

I'm perplexed..

H
0
 
LVL 6

Accepted Solution

by:
sodalitas earned 500 total points
Comment Utility
Ok, so the validation function assumes that anything not in a hidden div is appropriate for validating, and we have a situation where this is not the case, because the email_delivery section is being shown even though delivery type of email has not been chosen.

I see this as a presentation issue, they should match up.  So either (1) neither the email_delivery or postal_delivery sections are visible if there has been no selection in the drop down, and you only show the appropriate section once the value is chosen (ie default no selection for drop down and default hidden for both sections), or (2) you default the drop down box to either email or postal and you show the relevant section.

Personally, I would choose option 1.  I would think that you only show on the page the controls they are to fill out, and on page load you don't know if they should fill out the recipient email control since they haven't chosen email as the delivery type from the select box.
0
 

Author Comment

by:headbump
Comment Utility
S,

I think you're right and I will go that route...thanks for your help.

H
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

In this article, we'll look how to sort an Array in JavaScript, including the more advanced techniques of sorting a collection of records either ascending or descending on two or more fields. Basic Sorting of Arrays First, let's look at the …
JavaScript can be used in a browser to change parts of a webpage dynamically. It begins with the following pattern: If condition W is true, do thing X to target Y after event Z. Below are some tips and tricks to help you get started with JavaScript …
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)
The viewer will learn the basics of jQuery including how to code hide show and toggles. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery…

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

7 Experts available now in Live!

Get 1:1 Help Now