Validating Forms With CodeIgniter and JQuery

I created a JQuery Plugin, imValidateForm. As the name suggests, the plugin is used to validate forms. In this post, I will discuss how to use the imValidateForm plugin with CodeIgniter.

First download the plugin (Google Code or JQuery Plugins), create a folder named ‘js’ under root and copy the plugin to this location.

The Model

In this first example, I’ve created a members model to store member information. I’ll only display the relevant method (addMember).

class mMembers extends Model {
    	function mMembers() {
    		parent::Model();
	}	
	function addMember(){
		$d = date('Y-m-d H:i:s');
	        $data = array('first_name' => db_clean($_POST['first_name'],20),
				  'last_name' => db_clean($_POST['last_name'],20),
		                  'email' => db_clean($_POST['email'],60),
		                  'password' => db_clean(dohash($_POST['password']),16),
				  'user_level' => db_clean($_POST['user_level'],1),
				  'mod_date' => $d
		                  );
 
		$this->db->insert('members',$data);
		return '{"type": "message", "label": "Registration Complete"}';
	}
}

The addMember method inserts member information into the member table. The method returns a Json object that will be used by the imValidateForm plugin.

return '{"type": "message", "label": "Registration Complete"}';

The Controller

I created a member controller with a register method.

class Members extends Controller {
	var $mainMenu;
	var $title;
 
	function Members()	{
		parent::Controller();	
		@session_start();
		$this->mainMenu = array(
				'home'=>'welcome/index',
				'about us'=>'welcome/about_us',
				'tour info'=>'welcome/tour_info',
				'FAQ\'s'=>'welcome/faqs',
				'photo gallery'=>'welcome/photo_gallery',
				'contact'=>'welcome/contact'
				);
		$this->title = 'My Favorite Site';		
	}
 
        function register(){
	   	if ($this->input->post('email')){
	   		echo $this->mMembers->addMember();
	 	} else {
	  		$data['title'] = $this->title;
			$data['caption'] = "Member Registration";
			$data['navList'] = $this->mainMenu;
			$data['page'] = 'register';
			$this->load->vars($data);
			$this->load->view('main_validate');
		}
	}
}

If the email post var exists, call the addMember method of the Members model (when the form is submitted). Else, create the view. Two views are created: a page view and the main view.

$data['page'] = 'register';
$this->load->view('main_validate');

The Register View

The registration form is displayed on the register view.

<h3><?php echo $caption;?></h3>
 
<?php
$attr = array('id' => 'frmRegister');
echo form_open('members/register', $attr);
echo "<p><label for='first_name'>First Name</label><br/>";
$data = array('name'=>'first_name','id'=>'first_name','maxlength'=>20);
echo form_input($data) ."</p>";
 
echo "<p><label for='last_name'>Last Name</label><br/>";
$data = array('name'=>'last_name','id'=>'last_name','maxlength'=>20);
echo form_input($data) ."</p>";
 
echo "<p><label for='u'>Email</label><br/>";
$data = array('name'=>'email','id'=>'u','maxlength'=>50);
echo form_input($data) ."</p>";
 
echo "<p><label for='emailConf'>Confirm Email</label><br/>";
$data = array('name'=>'emailConf','id'=>'emailConf','maxlength'=>50);
echo form_input($data) ."</p>";
 
echo "<p><label for='password'>Password</label><br/>";
$data = array('name'=>'password','id'=>'password','maxlength'=>16);
echo form_password($data) ."</p>";
 
echo "<p><label for='passwordConf'>Confirm Password</label><br/>";
$data = array('name'=>'passwordConf','id'=>'passwordConf','maxlength'=>16);
echo form_password($data) ."</p>";
 
echo form_hidden('user_level', 'B');
 
$data = array(
    'name' => 'btnRegister',
    'id' => 'btnRegister',
    'content' => 'register'
);
 
echo form_button($data);
echo form_close();
?>
<div id="response"></div>

First I’m creating a form and assigning it an id of ‘frmRegister’. I’m also setting the action of the form, but this is not necessary because the action will be set by the plugin.

$attr = array('id' => 'frmRegister');
echo form_open('members/register', $attr);

Notice that instead of creating a submit button, I am creating a regular button, giving it an id of ‘btnRegister’.

$data = array(
    'name' => 'btnRegister',
    'id' => 'btnRegister',
    'content' => 'register'
);
 
echo form_button($data);

Also notice the response div at the bottom of the form. This div will be used to display validation errors.

<div id="response"></div>

The Main View

The main view will load JQuery, the imValidate Plugin, the validation rule file, and the register view. We’ll discuss the validation rule file last in this post.

<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
		<title><?php echo $title; ?></title>
		<link rel="stylesheet" href="<?= base_url(); ?>css/default.css" type="text/css" media="screen" />
		<script type="text/javascript" src="<?= base_url(); ?>js/jquery/jquery-1.3.2.min.js"></script>
		<script type="text/javascript" src="<?= base_url(); ?>js/jquery/jquery.imValidateForm-1.2.js"></script>
		<script type="text/javascript" src="<?= base_url(); ?>js/jquery/validate_json.js"></script> 
		<script type="text/javascript">
		$(document).ready(function(){
			$('#btnRegister').click(function() { 
				$('#frmRegister').imValidateForm({
					responseDiv:  'response',
					validate_func: 'validateFields',
					validate_map: valMapReg,
					url:"<?= base_url() . "index.php/members/register"; ?>",
					submit_button: 'btnRegister'
				});	
				return false;
			});
		});
		</script>
	</head>
	<body>
		<div id="body">
			<div id="banner"></div>
			<div id="menu"></div>
			<div id="page">
				<?php $this->load->view($page); ?>
			</div>
			<div id="sideBar">
				<?php $this->load->view('sideBar'); ?>
			</div>
		</div>
	</body>
</html>

When the user clicks the button ‘btnRegister’, the plugin is initialized.

$('#btnRegister').click(function() { 
	$('#frmRegister').imValidateForm({
                // the id of the div that will display the validation error(s)
		responseDiv:  'response',
                // always called. will create other functionality in the future
		validate_func: 'validateFields',
                // the validation map to use. located in the validate_json.js file
		validate_map: valMapReg,
                // the form action url
		url:"<?= base_url() . "index.php/members/register"; ?>",
                // the button is disabled after single click - prevents double-click
		submit_button: 'btnRegister'
	});	
	return false;
});

The Validation Map

The validation map are validation rules stored in a Javascript file in a JSON format. The name of the file can be anything. I named it validate_json.js. I store all validation maps for all forms in this file. Use the validate_map option of the plugin to tell the imValidateForm plugin which map to use.

?View Code JAVASCRIPT
validate_map: valMapReg

See my post: imValidateForm to view all the types of validation checks that can be made. You can also view my demo pages. The validation map for the registration form can be named anything. I try to choose a name that is associated with the form I am validating.

?View Code JAVASCRIPT
var valMapReg = { "fields": 
	[{"id": "first_name", "label" : "First Name", "rules":
						 [{"name": "hasValue"}]
	},
	 {"id": "last_name", "label": "Last Name", "rules":
						 [{"name": "hasValue"}]
	},
	{"id": "email", "label": "Email", "rules":
						 [{"name": "hasValue"}, {"name": "isValidEmail"}, {"name": "isEqual", "fields": [
				  				{"id" : "emailConf"}]}]
	},
	{"id": "password", "label": "Password", "rules":
						 [{"name": "hasValue"}, {"name": "isEqual", "fields": [
				  				{"id" : "passwordConf"}]}]
						}]
}

The first rule for the first_name field. It must have value, so the hasValue rule is being used. The id must be the id of the field that is to be checked. The label is what will be displayed to the user in case of an error:

First Name must have a value

The last_name validation is the same as the first_name.

The email field makes three checks:

  1. Must have value
  2. Must be a valid email
  3. The value of the email must be the same as the emailConf field on the form

Fairly simple. If the form fails any of these rules, the errors will display in the response div and the form will not submit.

In this next example, I will use the continue option to tell the plugin to another page after the form as been successfully submitted. This can be done two ways. I can add a form listener or I can just send a continue in the json object that is returned.

The Model

I have a mStudentInfo model with a method that will add student information to a students table. Unlike the previous addMember method that returns a json object, this method will only return true when it has finished processing.

class mStudentInfo extends Model {
    	function mStudentInfo() {
		parent::Model();
	}	
        function addStudent(){
	    $d = date('Y-m-d H:i:s');
	    $data = array('member_id' => $_POST['member_id'],
	    			  'child_name' => db_clean($_POST['child_name'],40),
				  'street_address' => db_clean($_POST['street_address'],30),
		                  'city' => db_clean($_POST['city'],40),
		                  'state_id' => $_POST['state_id'],
				  'zip_code' => db_clean($_POST['zip_code'],10),
				  'age' => db_clean($_POST['age'],2),
		                  'grade' => db_clean($_POST['grade'],2),
	    			  'gender' => db_clean($_POST['gender'],1),
		                  'high_school' => db_clean($_POST['high_school'],50),
		                  'counselor_name' => db_clean($_POST['counselor_name'],40),
				  'counselor_phone' => db_clean($_POST['counselor_phone'],12),
				  'emergency_notify_name' => db_clean($_POST['emergency_notify_name'],40),	
				  'emergency_notify_phone' => db_clean($_POST['emergency_notify_phone'],12),
				  'mod_date' => $d
		                  );
 
		$this->db->insert('student_info',$data);
		return true;
	}
}

The Controller

We have a Students controller that will be used to serve the student view pages. For brevity, I’m just going to the relevant method used in the controller.

function student_create() {
	if ($this->input->post('child_name')){
  		$r = $this->mStudentInfo->addStudent();
  		$this->session->set_flashdata('message','Student added');
  		echo '{"type": "continue", "label": "'.base_url() . "index.php/students/dashboard". '"}';
  	} else {
		$data['title'] = $this->title;
		$data['caption'] = "Add Student Info";
		$data['page'] = 'students/student_create_edit';
		$data['states'] = $this->mStates->getStates();
		$data['student'] = getTableColumns('student_info', true);
		$data['updType'] = 'create';
		$data['mId'] = $_SESSION['memberId'];
		$this->load->vars($data);
		$this->load->view('main_validate');    
	}
}

When the form is submitted, addStudent method is called. This method returns true. I then use the set_flashdata method to display a message on the page. Looking at the echo statement, you that the json object is of type ‘continue’. This tells the plugin to go to this url once the form is successfully posted.

$r = $this->mStudentInfo->addStudent();
$this->session->set_flashdata('message','Student added');
echo '{"type": "continue", "label": "'.base_url() . "index.php/students/dashboard". '"}';

The Student_create_edit View

There is a many more fields to validate in this view.

<h3><?php echo $caption;?></h3>
<p style="color:#ffffff;"><span class="required" style="margin-left:10px;">*</span> Denotes Required Field</p>
<?php
$attr = array('id' => 'frmStudent');
echo ($updType == 'create') ? form_open('students/student_create', $attr) : form_open('student/student_edit', $attr);
echo "<p><label for='child_name'>Child's Full Name</label><span class='required'>*</span><br/>";
$data = array('name'=>'child_name','id'=>'child_name','maxlength'=>40, 'value'=>$student['child_name']);
echo form_input($data) ."</p>";
 
echo "<p><label for='street_address'>Street Address</label><span class='required'>*</span><br/>";
$data = array('name'=>'street_address','id'=>'street_address','maxlength'=>20, 'value'=>$student['street_address']);
echo form_input($data) ."</p>";
 
echo "<p><label for='city'>City</label><span class='required'>*</span><br/>";
$data = array('name'=>'city','id'=>'city','maxlength'=>20, 'value'=>$student['city']);
echo form_input($data) ."</p>";
 
echo "<p><label for='state_id'>State</label><span class='required'>*</span><br/>";
echo "<select name='state_id' id='state_id'>";
if (count($states)) {
	foreach ($states as $key => $list) {
		$sel = ($list['state_id'] == $student['state_id']) ? 'selected="selected"' : '';
		echo "<option value='". $list['state_id'] . "'". $sel . ">" . $list['state_name'] . "</option>";
	}		
}	
echo "</select>";
 
echo "<p><label for='zip_code'>Zip Code</label><span class='required'>*</span><br/>";
$data = array('name'=>'zip_code','id'=>'zip_code','maxlength'=>16, 'value'=>$student['zip_code']);
echo form_input($data) ."</p>";
 
echo "<p><label for='age'>Age</label><span class='required'>*</span><br/>";
$data = array('name'=>'age','id'=>'age','maxlength'=>2, 'value'=>$student['age']);
echo form_input($data) ."</p>";
 
echo "<p><label for='gender'>Grade</label><span class='required'>*</span><br/>";
$options = array(
                  'M' => 'Male',
                  'F' => 'Female'
                );
echo form_dropdown('gender', $options, $student['gender']) ."</p>";
 
echo "<p><label for='high_school'>High School</label><span class='required'>*</span><br/>";
$data = array('name'=>'high_school','id'=>'high_school','maxlength'=>50, 'value'=>$student['high_school']);
echo form_input($data) ."</p>";
 
echo "<p><label for='grade'>Grade</label><span class='required'>*</span><br/>";
$options = array(
		  '0' => 'Select Grade',
                  '8' => '8th',
                  '9' => '9th',
                  '10' => '10th',
                  '11' => '11th',
		  '12' => '12th'
                );
echo form_dropdown('grade', $options, $student['grade']) ."</p>";
 
echo "<p><label for='counselor_name'>Counselor Name</label><br/>";
$data = array('name'=>'counselor_name','id'=>'counselor_name','maxlength'=>40, 'value'=>$student['counselor_name']);
echo form_input($data) ."</p>";
 
echo "<p><label for='counselor_phone'>Counselor Phone</label><br/>";
$data = array('name'=>'counselor_phone','id'=>'counselor_phone','maxlength'=>12, 'value'=>$student['counselor_phone']);
echo form_input($data) ."</p>";
 
echo "<p><label for='emergency_notify_name'>Emergency Notify Name</label><span class='required'>*</span><br/>";
$data = array('name'=>'emergency_notify_name','id'=>'emergency_notify_name','maxlength'=>12, 'value'=>$student['emergency_notify_name']);
echo form_input($data) ."</p>";
 
echo "<p><label for='emergency_notify_phone'>Emergency Notify Phone</label><span class='required'>*</span><br/>";
$data = array('name'=>'emergency_notify_phone','id'=>'emergency_notify_phone','maxlength'=>12, 'value'=>$student['emergency_notify_phone']);
echo form_input($data) ."</p>";
 
 
echo form_hidden('member_id',$mId);
$bVal = 'add student';
if ($updType == 'edit') {
	echo form_hidden('id',$student['student_info_id']);
	$bVal = 'update student';
}
 
$data = array(
    'name' => 'btnSubmit',
    'id' => 'btnSubmit',
    'content' => $bVal,
);
 
echo form_button($data);
 
echo form_close();
echo anchor('students/dashboard', 'Back To Dashboard');
?>
<div id="response"></div>

The Main View

The main view is basically the same as the previous, so I will just display the plugin initialization.

?View Code JAVASCRIPT
$(document).ready(function(){
	$('#btnSubmit').click(function() { 
		$('#frmStudent').imValidateForm({
				responseDiv:  'response',
				validate_func: 'validateFields',
				validate_map: valMapStudent,
				url:"<?= base_url(). 'index.php/students/student_create';?>",
				submit_button: 'btnSubmit'
		});	
		return false;
	});
});

When the user clicks the button ‘btnSubmit’, the plugin is initialized for the form ‘frmStudent’.

The Validation Map

The validation map is rather simple.

?View Code JAVASCRIPT
var valMapStudent = { "fields":
  [{"id": "child_name", "label" : "First Name", "rules":
                                    [{"name": "hasValue"}]
  },
  {"id": "street_address", "label": "Street Address", "rules":
                                    [{"name": "hasValue"}]
  },
  {"id": "city", "label": "City", "rules":
				   [{"name": "hasValue"}]
  },
  {"id": "state_id", "label": "State", "rules":
                                   [{"name": "hasValue", "exclude": "1"}]
  },									
  {"id": "zip_code", "label": "Zip Code", "rules":
				   [{"name": "hasValue"}, {"name": "isNum"}]
  },
  {"id": "age", "label": "Age", "rules":
				   [{"name": "hasValue"}]
  },
  {"id": "gender", "label": "Gender", "rules":
				   [{"name": "hasValue"}]
  },
  {"id": "high_school", "label": "High School", "rules":
				   [{"name": "hasValue"}]
  },
  {"id": "grade", "label": "Grade", "rules":
                                   [{"name": "hasValue", "exclude": "0"}]
  },
  {"id": "emergency_notify_name", "label": "Emergency Notify Name", "rules":
				   [{"name": "hasValue"}]
  },
  {"id": "emergency_notify_phone", "label": "Emergency Notify Phone", "rules":
				   [{"name": "hasValue"}]
  }]
}

I’m using two rules that I have not previously discussed.

  1. The ‘hasValue’ rule has an ‘exclude’ option. This is helpful when creating select elements (dropdowns). Because selects almost always have some value, I can use the exclude option to tell the plugin that the form element must have a value must it can’t be X. For instance, grade select element has a 0 option, but I want the user to select a grade.
    $options = array(
    		  '0' => 'Select Grade',
                      '8' => '8th',
                      '9' => '9th',
                      '10' => '10th',
                      '11' => '11th',
    		  '12' => '12th'
                    );
    echo form_dropdown('grade', $options, $student['grade']);

    So I tell the plugin that the form can’t be submitted if the grade element has a value of 0.

    ?View Code JAVASCRIPT
    {"id": "grade", "label": "Grade", "rules":
                                         [{"name": "hasValue", "exclude": "0"}]
    }
  2. The zip_code field uses the ‘isNum’ rule. As the name suggests, the field value must be a number. I guess that I don’t really need to use the hasValue rule with this field because an empty value is not a number.

That’s it. Again, to view all the options and other rules used by the imValidateForm plugin, see my post, imValidateForm. Enjoy.

Be Sociable, Share!

Checkout My New Site - T-shirts For Geeks