Link to home
Start Free TrialLog in
Avatar of headbump
headbump

asked on

making form fields required depending upon toggle state

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

Avatar of sodalitas
sodalitas

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
Avatar of headbump

ASKER

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
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.
Sorry, thats a[i+4], not a[5]
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
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
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
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.
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
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?
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
ASKER CERTIFIED SOLUTION
Avatar of sodalitas
sodalitas

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
S,

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

H