Dear All,
I have a page at this link http://183.78.169.54/v3/addTab.php. Then you can click the Driver Employment tab and add just two rows and press the Add button. Then it will take to Driver Details and show all the fields are required. The problem here is that the Driver Employment part I done using jquery the rest I did using normal javascript. So now how to get both working is my problem.

Recommended Answers

All 26 Replies

There's nothing to prevent raw javascript and jquery co-existing.

You just need to invoke appropriate code in response to relevant user events.

The code will typically be organised in functions, each of which can contain raw js or jquery or a mixture of the two.

You probably just need to reorganise the code that you have already written.

In this context, it is probably worth noting that any code sitting inside a $(document).ready(...) structure has access to all functions and variables in the global namespace - but not the other way round.

The preferred way ahead would be to recast everything in jquery.

Airshow

Dear Airshow,
Now what I want to do is actually those in the Driver Employment tab I want to validate using the jquery method. But the rest of I want to validate via the normal javascript. How to assign that accordingly. There is where I am stuck. Now both validation is working and messing things.

It's hard to describe what to do in general terms.

Can you post the relevant code? In particular, I need to see how event handlers are attached because that's the most likely area where conflict might arise.

Airshow

Dear Airshow,
Below is my codes and it is located here http://183.78.169.54/v3/addTab.php if you would like to test the site. One function is the javascript called validateForm() and another is the other is $(document).ready(function() {
. But when I pressed the add button it called the validateForm(); because I do this onSubmit="return validateForm();

<?php 
session_start(); 
require "KoolTabs/kooltabs.php";
require_once('config.php');
$searchcm=$_POST['searchcm'];
$formType="Add";
$submitTag="Add";
//$driverID=$_GET['driverID'];




?>


<html> 
<head> 
<link rel="stylesheet" type="text/css" href="my1.css" media="all"> 
<link rel="stylesheet" type="text/css" href="epoch_styles.css" />
<script type="text/javascript" src="epoch_classes.js"></script>
<script type="text/javascript">
/*You can also place this code in a separate file and link to it like epoch_classes.js*/
	var driverLicenseExpiryCal,driverGDLExpiryCal;
	
	var dp_cal,ms_cal;      
  window.onload = function () {
  
  driverLicenseExpiryCal  = new Epoch('epoch_popup','popup',document.getElementById('driverLicenseExpiryDate'));
	driverGDLExpiryCal  = new Epoch('epoch_popup','popup',document.getElementById('driverGDLExpiryDate'));
	
	
	document.getElementById("driverDetails").className = "show"; 
	document.getElementById("driverLicenses").className = "hide";
	document.getElementById("driverEmployment").className = "hide";

};
</script>
<script type="text/javascript">
function showTab(_id) 
{
	
	var tabID=_id;  
	
	//var class1 = document.getElementById("driverDetails").className; 
	//var class2 = document.getElementById("driverLicenses").className; 
	//var class3 = document.getElementById("driverNextOfKin").className; 
	
	<?php 		 
    $driverDetails=true;
    $driverLicenses='';
		$driverEmployment='';		

		?>
	if(tabID=="driverDetails")
	{
		<?php 		 
    $driverDetails=true;
    $driverLicenses=false;
		$driverEmployment=false;
		?>
		//alert("driverDetails : "+tabID);
		//document.getElementById(tabID).style.display = 'block'; 
		document.getElementById("driverDetails").className = "show"; 
		document.getElementById("driverLicenses").className = "hide";
		document.getElementById("driverEmployment").className = "hide";		
	}
	else if(tabID=="driverLicenses")
	{
		//alert("DD : "+tabID);
		document.getElementById("driverDetails").className = "hide"; 
		document.getElementById("driverLicenses").className = "show";
		document.getElementById("driverEmployment").className = "hide";
		<?php 		 
    $driverDetails='';
    $driverLicenses=true;
		$driverEmployment='';
		
		?>
	}
	
	else if(tabID=="driverEmployment")
	{
		//alert("DD : "+tabID);
		document.getElementById("driverDetails").className = "hide"; 
		document.getElementById("driverLicenses").className = "hide";
		document.getElementById("driverEmployment").className = "show";
		<?		 
    $driverDetails='';
    $driverLicenses='';
		$driverEmployment=true;
		?>
	}
}

function validateForm() 
{
			//alert("TEST");
			//Get the controls
			var driverNameControl = document.getElementById("driverName");
      var dateOfBirthDayControl = document.getElementById("dateOfBirthDay");
      var dateOfBirthMonthControl = document.getElementById("dateOfBirthMonth");
      var dateOfBirthYearControl = document.getElementById("dateOfBirthYear");
      var driverNewICNoControl = document.getElementById("driverNewICNo");
          
      var driverLicenseNoControl = document.getElementById("driverLicenseNo");
      var driverLicenseExpiryDateControl = document.getElementById("driverLicenseExpiryDate");
      var driverGDLNoControl = document.getElementById("driverGDLNo");
      var driverGDLExpiryDateControl = document.getElementById("driverGDLExpiryDate");
     
     
			//Create expressions
			var isNumeric = /^[0-9]+$/;
			var isLetters = /^[a-zA-Z ]+$/;
			var isEmail = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
			
			//Cheack each one and if it fails, set an appropriate error message
			var gotDriverNameError="false";
			var gotDateOfBirthError="false";
			var gotDriverNewICNoError="false";			
			
			var gotDriverLicenseNoError="false";
			var gotDriverLicenseExpiryDateError="false";
			var gotDriverGDLNoError="false";
			var gotDriverGDLExpiryDateError="false";
			
			//alert("client ID:"+clientNameControl.value+"TEST");
			//If name is empty or invalid
		
		  	
		  if(driverNameControl.value == "")
			{
				driverNameError.innerHTML = " * Driver Name is empty";
				gotDriverNameError="true";
			}
			else if(driverNameControl.value.search(isLetters))
			{
				driverNameError.innerHTML = " * Driver Name must only contain letters";
				gotDriverNameError="true";				
			}
			else
			{
				driverNameError.innerHTML = "";
			  gotDriverNameError="false";
		  }		  
      
      if(dateOfBirthDayControl.value>0 && dateOfBirthMonthControl.value>0 && dateOfBirthYearControl.value >0)
      {
      	  var myDate = new Date();
		      //alert("day : "+ dateOfBirthDayControl.value+"month : "+dateOfBirthMonthControl.value+"year : "+dateOfBirthYearControl.value);
		      myDate.setFullYear( dateOfBirthYearControl.value, dateOfBirthMonthControl.value-1, dateOfBirthDayControl.value );
          //alert("my date : "+myDate+"get month :"+myDate.getMonth());
      	  if ( myDate.getMonth() != dateOfBirthMonthControl.value-1 ) 
      	  {      
            driverDateOfBirthError.innerHTML = "In Valid Date";
			      gotDateOfBirthError="true";
		      }
		      else
		      {
		      	//alert(" valid date");
		      	driverDateOfBirthError.innerHTML = "";
			      gotDateOfBirthError="false";
		      }
      }
      else
      {
      	driverDateOfBirthError.innerHTML = "Select Data Of Birth";
			  gotDateOfBirthError="true";
      }      
      
      if(driverNewICNoControl.value == "")
			{
				driverNewICNoError.innerHTML = " * Driver New IC No is empty";
				gotDriverNewICNoError="true";
			}
			else if(driverNewICNoControl.value.search(isNumeric))
			{
				driverNewICNoError.innerHTML = " * Driver New IC No must only contain numbers";
				gotDriverNewICNoError="true";				
			}
			else
			{
				driverNewICNoError.innerHTML = "";
			  gotDriverNewICNoError="false";
		  }
		  		  
		  if(driverLicenseNoControl.value == "")
			{
				driverLicenseNoError.innerHTML = " * License No. is empty";
				gotDriverLicenseNoError="true";				
			}			
			else
			{
				driverLicenseNoError.innerHTML = "";
			  gotDriverLicenseNoError="false";
		  }
		  
		  if(driverLicenseExpiryDateControl.value == "")
			{
				driverLicenseExpiryDateError.innerHTML = " * License Expiry Date is empty";
				gotDriverLicenseExpiryDateError="true";				
			}			
			else
			{
				driverLicenseExpiryDateError.innerHTML = "";
			  gotDriverLicenseExpiryDateError="false";
		  }
		  
		  
		  
		  if(driverGDLNoControl.value == "")
			{
				driverGDLNoError.innerHTML = " * GDL No. is empty";
				gotDriverGDLNoError="true";				
			}			
			else
			{
				driverGDLNoError.innerHTML = "";
			  gotDriverGDLNoError="false";
		  }
		  
		  if(driverGDLExpiryDateControl.value == "")
			{
				driverGDLExpiryDateError.innerHTML = " * GDL Expiry Date is empty";
				gotDriverGDLExpiryDateError="true";				
			}			
			else
			{
				driverGDLExpiryDateError.innerHTML = "";
			  gotDriverGDLExpiryDateError="false";
		  }
		  
		 
			
			
			
			//If any errors occurred, return false, otherwise true
			if(gotDriverNameError=="true" || gotDateOfBirthError=="true" || gotDriverNewICNoError=="true")
			{
				showTab("driverDetails");
				return false;
			}
			else if(gotChild1DateOfBirthError=="true" || gotChild2DateOfBirthError=="true" || gotChild3DateOfBirthError=="true" )
			{
				showTab("driverNextOfKin");
				return false;
			}
			else 
				return true;
};
</script> 


<script src="http://code.jquery.com/jquery-1.5.1.min.js"></script> 
<script src="jquery.validate.js"></script> 
        
<script> 
        
        $(document).ready(function() {
        	  
            function setupSingleRowValidation(form) {
                function filledFields(array) {
                    // when given ['name', 'age'] this function will return the following string
                    // '[name="name"]:filled, [name="age"]:filled'
                    var selectors = [];
                    $(array).each(function (i, name) {
                        selectors.push('[name="' + name + '"]:filled');
                    });
                    //alert("Selector : "+selectors);
                    return selectors.join(', ');
                }
                function createSingleRowRule(field) {
                    var suffix = /\[.*\]/.exec(field),
                        name = 'name' + suffix,
                        durationOfEmployment = 'durationOfEmployment' + suffix,
                        reasonLeaving = 'reasonLeaving' + suffix;
                        previousRecords = 'previousRecords' + suffix;
                     //alert("sffux:"+suffix);
                    return {
                        required: filledFields([name, durationOfEmployment, reasonLeaving, previousRecords]),
                        number: (field === durationOfEmployment)
                    };
                }
                
                // clean up pre-existing rules before adding new ones
                $('tr td:not(:first) input', form).each(function () {
                    if ($(this.form).validate().currentElements.has(this).length) {
                        $(this).rules('remove');
                    }
                
                    var rule = createSingleRowRule(this.name);
                    $(this).rules('add', rule);
                });
                
                $('tr td:not(:first) textarea', form).each(function () {
                    if ($(this.form).validate().currentElements.has(this).length) {
                        $(this).rules('remove');
                    }
                
                    var rule = createSingleRowRule(this.name);
                    $(this).rules('add', rule);
                });
                
                // prepare single row rules
                var nameField = $('tr td input[name^="name"]', form);
                //var singleRowRules = createSingleRowRules(nameField.attr('name'));
                
                // initialize validation with single row rules
                $(form).validate({
                    /*rules: singleRowRules,*/
                    debug: true
                });
            }
            function setupMultipleRowValidation(form) {
                // clean up fields so that they contain the multiple row validation rules
                /*$(form).validate().currentElements.each(function () {
                    $(this).rules('remove');
                });*/
                
                $('td:not(:first) input', form).each(function () {
                    $(this).rules('add', {required: true});
                });
                $('td:not(:first) textarea', form).each(function () {
                    $(this).rules('add', {required: true});
                });
                $('[name^="durationOfEmployment"]', form).each(function () {
                    $(this).rules('add', {number: true});
                });
            };
            function setupFormValidation(form) {
                $(form).validate().resetForm();
                //alert("LEnght : "+$('tbody tr', form).length);
                if ($('tbody tr', form).length > 1) {
                	  //alert("Call setup multiple row");
                    setupMultipleRowValidation(form);
                } else {
                    $(form).validate().resetForm();
                    setupSingleRowValidation(form);
                }
            }
            
            var form = $("#form1");
            setupFormValidation(form);
 
            var prot = $('tr.prototype').clone().removeClass('prototype');
            $(form).data('prototype', prot);
            
            var id = $(document).data('idCounter') || 0;
 
            // Add button functionality
            $("table.dynatable button.add").click(function() {
                var form = this.form;
                id++;
                
                // Get a new row based on the prototype row
                //var prot = master.find(".prototype").clone();
                var prot = $(form).data('prototype').clone();
                prot.find('[name^="id"]').attr("value", id);
                prot.find('[name^="name"]').attr('name', 'name[' + id + ']');
                prot.find('[name^="name"]').attr('value', '');
                prot.find('[name^="duration"]').attr('name', 'durationOfEmployment[' + id + ']');
                prot.find('[name^="duration"]').attr('value', '');
                prot.find('[name^="reasonLeaving"]').attr('name', 'reasonLeaving[' + id + ']');
                prot.find('[name^="reasonLeaving"]').attr('value', '');                
                prot.find('[name^="previousRecords"]').attr('name', 'previousRecords[' + id + ']');
                prot.find('[name^="previousRecords"]').attr('value', '');                
                
                $(form).find("tbody").append(prot);
 
                setupFormValidation(form);
                return false;
            });
            
            // Remove button functionality
            $("table.dynatable button.remove").live("click", function() {
               
                var form = this.form;
 
                $(this).closest("tr").remove();
                setupFormValidation(form);
            });
            
            jQuery('.dOnly').live('keyup', function () 
            {     
                 this.value = this.value.replace(/[^0-9\.]/g,''); 
            });
        });
</script> 
<style> 
            .dynatable {
                border: solid 1px #000; 
                border-collapse: collapse;
            }
            .dynatable th,
            .dynatable td {
                background-color:#ccc; 
                font-size:14px;
                font-color:#ffffff;
                font-family:Calibri;
            }
            .dynatable .prototype {
                
            }
            label.error 
            { 
            	display: block; 
            	color:red;
            }
            
            td { vertical-align: top; }
            
</style> 

</head> 
<body> 

<?
    $driverDetails=true;
    $driverLicenses='';
		$driverEmployment='';
		echo "TEst DriverDetails : ".$driverDetails;
    $kts = new KoolTabs("kts");
 
		//Step 3: Set properties for kooltabs
		$kts->styleFolder = "KoolTabs/styles/silver";
		 
		//Step 4: Add tabs for KoolTabs: addTab($parentid,$id,$text,$link)
		$kts->addTab("root","Driver Details","Driver Details","javascript:showTab(\"driverDetails\")",$driverDetails);
		$kts->addTab("root","Driver Licenses","Driver Licenses","javascript:showTab(\"driverLicenses\")",$driverLicenses);
		$kts->addTab("root","Driver Employment","Driver Employment","javascript:showTab(\"driverEmployment\")",$driverEmployment);
		
    echo $kts->Render(); 

?>
<div >
	<h2 class="form_desicription">Add Driver (Draft)<?=$status?></h2>
</div>



<form action="<?=$_SERVER['PHP_SELF']?>" method="post" name="form1" enctype="multipart/form-data" id=form1 onSubmit="return validateForm();">
<div id="driverDetails" class="show" style="position:relative" >
	<table>
		
		
		
		<tr>
			<td>				
			  <label class=description for=element_1>Name<font color="red">*</font></label> 
			</td>
			<td>
			  <input class="text"  id="driverName" name="driverName" value="<?php echo $driverName?>">  
			</td>
		</tr>
		<tr>
			<td><p class=error id="driverNameError" ></p></td>
		  <td></td>
		</tr>
		
		<tr>
			<td>				
			  <label class="description">Date of Birth<font color="red">*</font></label>
			</td>
			<td>
			  <?php
        echo "<select class='select' id='dateOfBirthDay' name='dateOfBirthDay' > ";
        echo "<option value=''>-Day-</option>";
        for($d=1;$d<32;$d++)
        {
	        if($d<10)
	        {
	        	$d="0".$d;
	        }
	        if($d==$dateOfBirthDay)
		      {
		       echo "<option selected value=".$d.">".$d."</option>";
		      }
		      else
		      {
		       echo "<option value=".$d.">".$d."</option>";
		      }
	      }
        echo "</select>";
        ?>
        
        <?php
        echo "<select class='select' id='dateOfBirthMonth' name='dateOfBirthMonth' > ";
        echo "<option value=''>-Month-</option>";
        for($m=1;$m<13;$m++)
        {
	        if($m<10)
	        {
	        	$m="0".$m;
	        }
	        if($m==$dateOfBirthMonth)
		      {
		       echo "<option selected value=".$m.">".$m."</option>";
		      }
		      else
		      {
		       echo "<option value=".$m.">".$m."</option>";
		      }
	      }
        echo "</select>";
        ?>
        <?php
        echo "<select class='select' id='dateOfBirthYear' name='dateOfBirthYear' > ";
        echo "<option value=''>-Year-</option>";
        for($y=1940;$y<1995;$y++)
        {
	        if($y==$dateOfBirthYear)
		      {
		       echo "<option selected value=".$y.">".$y."</option>";
		      }
		      else
		      {
		       echo "<option value=".$y.">".$y."</option>";
		      }
	      }
        echo "</select>";
        ?>
        <label class="description">(dd/mm/yyyy)</label> 
			</td>
		</tr>	
		<tr>
			<td><p class=error id="driverDateOfBirthError" ></p></td>
		  <td></td>
		</tr>
		
		<tr>
			<td>				
			  <label class=description >New I/C No:<font color="red">*</font></label> 
			</td>
			<td>
			  <input class="text" id="driverNewICNo" name="driverNewICNo" value="<?php echo $driverNewIcNo?>"> 	  
			</td>
		</tr>
		<tr>
			<td><p class=error id="driverNewICNoError" ></p></td>
		  <td></td>
		</tr>
		
		<tr>
			<td>				
			  <label class=description for=element_1>Recent Image</label> 
			</td>
			<td>			
			  <input type="file" class="file" id="driverImage" name="driverImage" value="" size="50px">
			</td>
		</tr>
		
	
		<tr>
			<td>				
			  <label class=description >Address:</label> 
			</td>
			<td>
			  <textarea rows="5" cols="20" class="textarea" id="driverAddress" name="driverAddress"></textarea>
			</td>
		</tr>
		
		
		
		
		<tr>
			<td>				
			  <label class=description for=element_1>Home Tel No:</label> 
			</td>
			<td>
			  <input class="text" id="driverTelHome" name="driverTelHome" value="<?php echo $driverTelHome?>"> 	  
			</td>
		</tr>	
		<tr>
			<td><p class=error id="driverTelHomeError" ></p></td>
		  <td></td>
		</tr>	
		
		<tr>
			<td>				
			  <label class=description for=element_1>Mobile Tel No:</label> 
			</td>
			<td>
			  <input class="text" id="driverTelMobile" name="driverTelMobile" value="<?php echo $driverTelMobile?>"> 	  
			</td>
		</tr>	
		<tr>
			<td><p class=error id="driverTelMobileError" ></p></td>
		  <td></td>
		</tr>
	</table>
</div>	
<div id="driverLicenses" class="show" style="position:relative" >				
  <table>		
		<tr>
			<td>				
			  <label class=description for=element_1>License No:<font color="red">*</font></label> 
			</td>
			<td>
			  <input class="text" id="driverLicenseNo" name="driverLicenseNo" value="<?php echo $driverLicenseNo?>"> 	  
			</td>
		</tr>
		<tr>
			<td><p class=error id="driverLicenseNoError" ></p></td>
		  <td></td>
		</tr>
		
		
		<tr>
			<td>				
			  <label class=description for=element_1>License Expiry Date:<font color="red">*</font></label> 
			</td>
			<td>
			  <input class="text" id="driverLicenseExpiryDate" name="driverLicenseExpiryDate" value="<?php echo $driverLicenseExpiryDate?>"> 	  
			  <input class="buttons" type="button" value="Pick" onclick="driverLicenseExpiryCal.toggle();"/>
			</td>
		</tr>
		<tr>
			<td><p class=error id="driverLicenseExpiryDateError" ></p></td>
		  <td></td>
		</tr>	
		
		<tr>
			<td>				
			  <label class=description for=element_1>License Image</label> 
			</td>
			<td>			
			  <input type="file" class="file" id="driverLicenseImage" name="driverLicenseImage" value="" size="50px">
			</td>
		</tr>
		
		<tr>
			<td>				
			  <label class=description for=element_1>GDL License No:<font color="red">*</font></label> 
			</td>
			<td>
			  <input class="text" id="driverGDLNo" name="driverGDLNo" value="<?php echo $driverGDLNo?>"> 	  
			</td>
		</tr>
		<tr>
			<td><p class=error id="driverGDLNoError" ></p></td>
		  <td></td>
		</tr>
		
		<tr>
			<td>				
			  <label class=description for=element_1>GDL License Expiry Date:<font color="red">*</font></label> 
			</td>
			<td>
			  <input class="text" id="driverGDLExpiryDate" name="driverGDLExpiryDate" value="<?php echo $driverGDLExpiryDate?>"> 	  
		   <input class="buttons" type="button" value="Pick" onclick="driverGDLExpiryCal.toggle();"/>
			</td>
		</tr>	
		<tr>
			<td><p class=error id="driverGDLExpiryDateError" ></p></td>
		  <td></td>
		</tr>
		
		<tr>
			<td>				
			  <label class=description for=element_1>GDL License Image</label> 
			</td>
			<td>			
			  <input type="file" class="file" id="driverGDLImage" name="driverGDLImage" value="" size="50px">
			</td>
		</tr>	
	</table>
</div>

<div id="driverEmployment" class="hide" style="position:relative" >

	<table class="dynatable"> 
		     <thead> 
                <tr> 
                    <th>ID</th> 
                    <th>Name Of Former Emp.</th> 
                    <th>Duration of Emp.</th> 
                    <th>Reason for Leaving Emp.</th> 
                    <th>Previous Incidents or Records</th> 
                    <th><button class="add">Add</button></th> 
                </tr> 
            </thead> 
            <tbody> 
            	  <tr class="prototype"> 
                        <td><input type="text" name="id[]" value="0" /></td> 
                        <td><input type="text" name="name[]" value="" /></td> 
                        <td><input type="text" name="durationOfEmployment[]" value="" /></td> 
                        <td><textarea rows=2 cols=15 name="reasonLeaving[]" /></textarea></td> 
                        <td><textarea rows=2 cols=15 name="previousRecords[]" /></textarea></td> 
                        <td><button class="remove">Remove</button> 
                    </tr> 
            </tbody>
   </table>
 		
			  <input class="buttons" type="Submit" name="<?php echo $submitTag?>" value="<?php echo $submitTag?>">
		
			  <input class="buttons" type="Reset" name="Reset" value="Reset" onclick="location.href='addDriverDraft.php'">			  
			
</div>

</form>



</body> 
</html>

I guess that the jquery validator hijacks the onSubmit="return validateForm() handler. If so, then it's a question of invoking validateForm() from inside $(document).ready(...) somehow. Will probably need to penetrate the jquery.validate plugin.

Currently using my netbook. Will have a closer look on my desktop machine later today/tomorrow.

Airshow

Dear Airshow,
Yes you are right. The problem is that find that jquery is best for the Driver Employment as it can cater well for the dynamic rows added and do the error checking. So I am like stuck at one hand I need the javascript and on the other hand I need the jquery. Thank you for looking into it.

Hi,

The first and easiest thing to try is

  1. Remove onsubmit="return validateForm()" from the form tag.
  2. Add $(form).submit(validateForm); to setUpFormValidation:
function setupFormValidation(form) {
  $(form).validate().resetForm();
  //alert("LEnght : "+$('tbody tr', form).length);
  if ($('tbody tr', form).length > 1) {
    //alert("Call setup multiple row");
    setupMultipleRowValidation(form);
  } else {
    $(form).validate().resetForm();
    setupSingleRowValidation(form);
  }
  $(form).submit(validateForm);
}

If $(form).validate() conforms to a standard "observer pattern" then I think this will work. If it doesn't work, then try adding the new line at the top of the function instead of the bottom.

Airshow

Dear Airshow,
Actually I managed to solve my problem my splitting into two forms those with javascript into one form tag and the last tab Driver Employment is into another tab. You can see here http://183.78.169.54/v3/addTab.php. The problem now when you use chrome and try to submit it will go back to Driver Details and show you the error. But that is not the case in IE. Why do you think so?

n14,

I can't immediately see why the browsers should behave differently and I'm not sure that splitting the form is the right solution because only one of the two forms will be submitted.

I think the approach in my previous post has more mileage in it even if it's not yet 100% correct.

Airshow

Dear Airshow,
If I put this at the bottom $(form).submit(validateForm); the jquery error overide the javascript error. If put right at the top no validation done and straight submit the form. You can try here http://183.78.169.54/v3/addTab.php.

n14,

OK, the simple approach doesn't work then.

If you can't live with your two form approach, then I think the way ahead is to redefine your current validateForm function as one or more custom validation methods of the validate plugin.

I've not done this myself but the API seems pretty clear.

Airshow

Dear Airshow,
I dont quite get the custom validation method? It have to be linked to which form the non Driver Employee is it? Thank you.

n14,

If your application is OK with two forms, then do nothing more.

If you need to recombine the two forms into one, then the custom validation method is a possible way ahead.

Airshow

Dear Airshow,
The problem is that it works fine in chrome wheere it will validate my other tabs when the Driver Employment is empty. Where as in IE it will just submit the form wihout validating the rest of the tabs. So how to work around this custom validation can you give a hint or example?

n14,

Before trying custom validation, I have discovered a "submitHandler" option, which provides a "callback for handling the actual submit when the form is valid."

Thus, we have a mechanism for calling validateForm() , without using onsubmit="validateForm()" , which we know gets hijacked by .validate() .

If I'm right, you just need to specify a submitHandler in your setupFormValidation function, like this.

function setupFormValidation($form) {
		$form.validate({
			submitHandler: function(form) {
				if(validateForm()) {
					form.submit();
				}
			}
		}).resetForm();
		if ($('tbody tr', $form).length > 1) {
			setupMultipleRowValidation($form);
		} else {
			setupSingleRowValidation($form);
		}
	}

This should allow you to re-combine your two forms into one.

Airshow

I will see if I can make a working copy of the page when I get home later this weekend.

Airshow

n14,

The main problem is that the function setupFormValidation expects a jquery object $("#form1") to be passed to it, but in two of three calls the DOM node form is passed.

This is easily fixed but we can go further. It would make for much more efficient code if the result of $("#form1") was used directly throughout $(document).ready(function(){...} thus avoiding the need to pass form, and re-evaluating $(form) in several places. We can do this, even in the inner functions, by exploiting javascript's "closure" feature.

The code simplifies in several places giving:

$(document).ready(function() {
	var $form = $("#form1");//this line moved to top of function for clarity
	//$form is then used throughout the function, including inner functions.

	function setupSingleRowValidation() {
		function filledFields(array) {
			// when given ['name', 'age'] this function will return the following string
			// '[name="name"]:filled, [name="age"]:filled'
			var selectors = [];
			$(array).each(function (i, name) {
				selectors.push('[name="' + name + '"]:filled');
			});
			//alert("Selector : "+selectors);
			return selectors.join(', ');
		}
		function createSingleRowRule(field) {
			var suffix = /\[.*\]/.exec(field),
				name = 'name' + suffix,
				durationOfEmployment = 'durationOfEmployment' + suffix,
				reasonLeaving = 'reasonLeaving' + suffix;
				previousRecords = 'previousRecords' + suffix;
			//alert("sffux:"+suffix);
			return {
				required: filledFields([name, durationOfEmployment, reasonLeaving, previousRecords]),
				number: (field === durationOfEmployment)
			};
		}
		// clean up pre-existing rules before adding new ones
		$('tr td:not(:first) input', $form).each(function () {
			if ($form.validate().currentElements.has(this).length) {
				$(this).rules('remove');
			}
			var rule = createSingleRowRule(this.name);
			$(this).rules('add', rule);
		});
		$('tr td:not(:first) textarea', $form).each(function () {
			if ($form.validate().currentElements.has(this).length) {
				$(this).rules('remove');
			}
			var rule = createSingleRowRule(this.name);
			$(this).rules('add', rule);
		});
		// prepare single row rules
		var nameField = $('tr td input[name^="name"]', $form);
		//var singleRowRules = createSingleRowRules(nameField.attr('name'));
		// initialize validation with single row rules
		$form.validate({
			/*rules: singleRowRules,*/
			debug: true
		});
	}
	function setupMultipleRowValidation() {
		// clean up fields so that they contain the multiple row validation rules
/*
		$form.validate().currentElements.each(function () {
			$(this).rules('remove');
		});
*/
		$('td:not(:first) input', $form).each(function () {
			$(this).rules('add', {required: true});
		});
		$('td:not(:first) textarea', $form).each(function () {
			$(this).rules('add', {required: true});
		});
		$('[name^="durationOfEmployment"]', $form).each(function () {
			$(this).rules('add', {number: true});
		});
	};
	function setupFormValidation() {
		$form.validate({
			submitHandler: function(form) {//DOM node "form" is correct here
				if(validateForm()) {
					form.submit();//safer than the jquery equivalent to avoid possibilitry of recursive validation
				}
			},
			//*** start: optional ***
			invalidHandler: function() {//call validateForm when $form.validate() indicates form is invalid.
				validateForm();
			}
			//*** end: optional ***
		}).resetForm();
		if ($('tbody tr', $form).length > 1) {
			setupMultipleRowValidation();
		}
		else {
			setupSingleRowValidation();
		}
	}
	setupFormValidation();
	var prot = $('tr.prototype').clone().removeClass('prototype');
	$form.data('prototype', prot);
	var id = $(document).data('idCounter') || 0;
	// Add button functionality
	$("table.dynatable button.add").click(function() {
		id++;
		// Get a new row based on the prototype row
		//var prot = master.find(".prototype").clone();
		var prot = $form.data('prototype').clone();
		prot.find('[name^="id"]').attr("value", id);
		prot.find('[name^="name"]').attr('name', 'name[' + id + ']').attr('value', '');
		prot.find('[name^="duration"]').attr('name', 'durationOfEmployment[' + id + ']').attr('value', '');
		prot.find('[name^="reasonLeaving"]').attr('name', 'reasonLeaving[' + id + ']').attr('value', '');
		prot.find('[name^="previousRecords"]').attr('name', 'previousRecords[' + id + ']').attr('value', '');
		$form.find("tbody").append(prot);
		setupFormValidation();
		return false;
	});
	// Remove button functionality
	$("table.dynatable button.remove").live("click", function() {
		$(this).closest("tr").remove();
		setupFormValidation();
	});
	$('.dOnly').live('keyup', function () {
		this.value = this.value.replace(/[^0-9\.]/g,'');
	});
});

Several comments in code

You will see that I've added an optional invalidHandler function. Delete this if you want validateForm() not to be called when .validate() fails.

I also had to fix an error in validateForm() (gotClientNameError doesn't exist) but maybe this was just in my copy (which I tidied and may have mis-edited).

Something else you might like to consider is your "prototype" implementation. As it stands, the prototype can be removed. It's safer for prototype HTML to be permanently hidden such that it is never itself used, and its "remove" button cannot be clicked. The user only ever sees the clones.

Airshow

Dear Airshow,
Great your changes work but the problem I notice now is that both the error appear meaning that my javascript and also jquery error appears. What is the invalidHandler is for exactly? Can you see how to avoid this problem? Thanks.

Great your changes work but the problem I notice now is that both the error appear meaning that my javascript and also jquery error appears.

That is exactly what we have been trying to achieve; to make both the .validate plugin AND your validateForm() function to run!

What is the invalidHandler is for exactly? Can you see how to avoid this problem? Thanks.

  • invalidHandler is a .validate() option that defines a custom handler (function). If, on form submission, validation by .validate() fails, this handler runs thus allowing other code of your choosing to be executed. The custom code can allow form submission despite .validate() having failed.
  • submitHandler is a .validate() option that defines a custom handler (function). If, on form submission, validation by .validate() is successful, this handler intercepts form submission such that other code of your choosing can be executed. The custom code can allow or suppress form submission.

You can read more here.

The two handlers can be edited/deleted to give the exact behaviour you want.

Airshow

Dear Airshow,
I have read some details now.Please corrcet me here so first under the submitHandler I call the validateForm() if is true I call the form.submit. So I guess then next it will submit the form via jquery am I right? Then why do we call the invalidateHandler? When it will be called? So then why do we resetForm? Why still the jquery error appear together with the javascript error?

if(validateForm()) {					form.submit();//safer than the jquery equivalent to avoid possibilitry of recursive validation				}			},			//*** start: optional ***			invalidHandler: function() {//call validateForm when $form.validate() indicates form is invalid.				validateForm();

}

Please corrcet me here so first under the submitHandler I call the validateForm() if is true I call the form.submit. So I guess then next it will submit the form via jquery am I right?

Nearly correct. form.submit() is regular javascript, not jquery.

Then why do we call the invalidateHandler? When it will be called?

submitHandler and invalidHandler are mutually exlusive; on any particular occasion that the user attempts to submit the form, one or the other of these handlers is called, not both.

So then why do we resetForm?

I don't know why the form is reset at that point. That is a remnant of your original code. It seems wrong to me too because it will blitz all user entries every time setupFormValidation() is called.

Why still the jquery error appear together with the javascript error?

All I know is that you wanted the jquery validate plugin AND the function validateForm() , written in standard javascript, to run. In the code I have given you, all the functionality of both approaches is maintained. I have not attempted to detect or resolve any conflicts. If they conflict, then you will need to make changes to make them compatible with each other.

Airshow

Dear Airshow,
How is the decision made to call either of this submitHandler and invalidHandler ? Another then when the regular form submit happen then how will this effect the jquery part of it?

How is the decision made to call either of this submitHandler and invalidHandler ? Another then when the regular form submit happen then how will this effect the jquery part of it?

That is explained in the validate plugin documentation and I gave a further (better?) explanation in my post above (2 days ago).

In short, on attempted form submission, validate will determine either "valid" or "invalid" depending on what the user has entered. If "valid", then the submitHandler will run; alternatively if "invalid" then the invalidHandler will run.

You are not obliged to have both a submitHandler and an invalidHandler. If either of these actions is not appropriate, then you can delete the corresponding block of code.

Airshow

Dear Airshow,
When the form.submit is called the whole form is submit is it? Another thing when you say "In short, on attempted form submission, validate will determine either "valid" or "invalid" depending on what the user has entered. If "valid", then the submitHandler will run; alternatively if "invalid" then the invalidHandler will run" The validate will determing the jquery part only rite?

When the form.submit is called the whole form is submit is it?

Correct. Standard HTML form submission. Not ajax.

Another thing when you say "In short, on attempted form submission, validate will determine either "valid" or "invalid" depending on what the user has entered. If "valid", then the submitHandler will run; alternatively if "invalid" then the invalidHandler will run" The validate will determing the jquery part only rite?

Correct (or more correctly, the validate plugin part). As written, the submitHandler and invalidHandler add the functionality of validateForm() .

Airshow

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.