Solved

making form fields required depending upon toggle state

Posted on 2006-11-08
13
660 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 6
13 Comments
 
LVL 6

Expert Comment

by:sodalitas
ID: 17899585
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
ID: 17899764
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
ID: 17899954
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
Salesforce Made Easy to Use

On-screen guidance at the moment of need enables you & your employees to focus on the core, you can now boost your adoption rates swiftly and simply with one easy tool.

 
LVL 6

Expert Comment

by:sodalitas
ID: 17899964
Sorry, thats a[i+4], not a[5]
0
 

Author Comment

by:headbump
ID: 17900763
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
ID: 17901136
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
 

Author Comment

by:headbump
ID: 17901363
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
ID: 17901724
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
ID: 17901774
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
ID: 17906281
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
ID: 17906759
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
ID: 17908009
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
ID: 17908039
S,

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

H
0

Featured Post

The Ultimate Checklist to Optimize Your Website

Websites are getting bigger and complicated by the day. Video, images, custom fonts are all great for showcasing your product/service. But the price to pay in terms of reduced page load times and ultimately, decreased sales, can lead to some difficult decisions about what to cut.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In my daily work (mainly using ASP.net), I need to write a lot of JavaScript code. One of the most repetitive tasks I do are the jQuery Ajax calls. You know: (CODE) I don't know if for you it's the same, but for me is soooo tedious to write the …
This article demonstrates how to create a simple responsive confirmation dialog with Ok and Cancel buttons using HTML, CSS, jQuery and Promises
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…

687 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