I will present it on example of registration form in which we want to check if given field is valid after the field is updated (so, it's kind of registration form with validation of user data on the fly).
Let's assume that registration form is held by the "register" action in UsersController, and the action which validates the fields (and to which we make AJAX call) is "verify".
- Include JsHelper in your controller where you want to use it.
You should also define which JavaScript library you want to use. Default is JQuery, I use Prototype.public $helpers = array('Js'=>array('Prototype'));
- If you use Security component in your controller, you should disable validatePost and csrfCheck in the action to which you make an AJAX call.
In our example with validating registration form - we should turn off validatePost and csrfCheck for the "verify" action. This can be done in the beforeFilter() function inside our controller:public function beforeFilter() {
parent::beforeFilter();
if($this->params['action']=='verify') {
$this->Security->validatePost=false;
$this->Security->csrfCheck=false;
}
} - Next, you should include a JavaScript library which you use, in the top of the view where the form is displayed (in our example - in "register" view).
<?php echo $this->Html->script('prototype',false);?>
(If you set the second parameter to false, the script will be put into the <head> section).
Of course if the library has already been included in the layout for other purposes - you don't need to double it in the view. - Next, in the layout which holds the registration form, you should add a
writeBuffer method, which will output buffered scripts. The writeBuffer
method should be placed before the </body> tag.
<?php if($this->params['action']=='register'):?>
<?php echo $this->Js->writeBuffer();?>
<?php endif;?> - Now, let's create a simple registration form with empty message div's to update after field validation:
<?php echo $this->Form->create('User',array('controller'=>'users','action'=>'register'))?>
<div>
Login: <?php echo $this->Form->text('login',array('id'=>'login'));?>
<div id="message-login"></div>
</div>
<div>
Password: <?php echo $this->Form->text('password',array('id'=>'password'));?>
<div id="message-password"></div>
</div>
<?php echo $this->Form->submit('Register',array('div'=>false))?></div>
<?php echo $this->Form->end();?> - Next, add JsHelper event "onchange" for both fields (of course you can change the event from "change", which will update given element after you leave the input, to any other of the
normal DOM events, such as "keyup" for "onkeyup", "click" for "onclick" etc.):
<?php echo $this->Form->create('User',array('controller'=>'users','action'=>'register'))?>
<div>
Login: <?php echo $this->Form->text('login',array('id'=>'input_login'));?>
<div id="message-login"></div>
<?php $this->Js->get('#input_login');?>
<?php
echo $this->Js->event('change',
$this->Js->request(
'/users/verify/login',
array(
'method'=>'post',
'async'=>true,
'update'=>'#message-login',
'dataExpression'=>true,
'data'=>'$("input_login").serialize()',
)
)
);
?>
</div>
<div>
Password: <?php echo $this->Form->text('password',array('id'=>'input_password'));?>
<div id="message-password"></div>
<?php $this->Js->get('#input_password');?>
<?php
echo $this->Js->event('change',
$this->Js->request(
'/users/verify/password',
array(
'method'=>'post',
'async'=>true,
'update'=>'#message-password',
'dataExpression'=>true,
'data'=>'$("input_password").serialize()',
)
)
);
?>
</div>
<?php echo $this->Form->submit('Register',array('div'=>false))?></div>
<?php echo $this->Form->end();?> - Your "verify" function could look like this:
public function verify($field) {
Of course you should define the $validate variable in the model to verify if the given field validates.
$this->layout = 'blank';
if($field!=NULL) {
$fields=array('login','password');
if(in_array($field,$fields)) {
App::uses('Sanitize','Utility');
Sanitize::clean($this->request->data['User'][$field]);
$this->User->set($this->request->data);
if(!$this->User->validates()) {
$this->validateErrors($this->User);
$errors=$this->validationErrors;
$this->set('errors',$errors);
}
$this->set('field',$field));
}
}
}
- The AJAX view for "verify" could look like this:
<?php if(isset($errors[$field]) && !empty($errors[$field])):?>
<div class="error-message">
<?php foreach($errors[$field] as $error):?>
<?php echo $error?><br/>
<?php endforeach;?>
</div>
<?php else:?>
OK
<?php endif;?>
Above solution allows to retrieve the value of only one field from the form.
If you need to retrive more than one field from a form (for example if you want to compare "password" and "repeat password" fields), you should set the 'data' option as follows:
<?php $this->Js->get('#id_of_field_to_observe');?>
<?php
echo $this->Js->event('change',
$this->Js->request(
array('controller'=>'controller','action'=>'action', parameters),
array(
'method'=>'post',
'async'=>true,
'update'=>'#id_of_element_to_update',
'dataExpression'=>true,
'data'=>$this->Js->serializeForm(array('isForm'=>false, 'inline'=>true))
)
)
);
?>
This will allow you to retrieve data from whole form.
Have fun playing with JsHelper;-)