Ajax Login form with validation errors inside jQuery modal dialog

I would like to share my little experience with Yii to the community in the form of the below small wiki:

I will demonstrate the user login and logout functionality along with validation errors using aweswome Yiiframework. The blog demo supplied with the standard framework download, provides a simple user login/logout functionality to demonstrate the core framework features. We will add some Ajax functions to this to display login form inside a jQuery modal dialog box with login errors if any. I do make use of ajaxSubmitButton( inside CActiveForm) to add ajax code to the submit button, CJuiDialog for modal dialog box. I will also show you how to separate login action(actionLogin in SiteController) into a separate class file(getLogin) that extends CAction, and later use this class as an action dynamically inside any controller. I use a widget class(loginProvider) and its action(GetLogin) for this purpose. I will now show you what modifications need to be done to the demo application:

  • Create a file named loginProvider.php and place it inside the components directory.
<?php
 
class loginProvider  extends CWidget{
            
    public static function actions(){
        return array(
                   'GetLogin'=>'application.components.actions.getLogin',
        );
    }
    
    public function run(){
       
        $this->renderContent();
     
    }
     
    protected function renderContent(){
  
 echo '<span style="float:right;">';
 if(Yii::app()->user->isGuest){
            echo CHtml::link('Login', array('/site/login.GetLogin'), array('onclick'=>'$("#login-dialog").dialog("open"); return false;'));
     echo '</span>';
     $this->getController()->renderPartial('application.components.views.login',array('model'=>new LoginForm)); 
 }
 else      
     echo CHtml::link('Logout ('.Yii::app()->user->name.')', array('site/logout'), array('visible'=>!Yii::app()->user->isGuest));
 echo '</span>';
   }
  
}
  • Create a directory named actions inside components directory.
  • Create the action class with name getLogin.php and place it inside components/actions directory.
<?php
 
class getLogIn extends CAction{
        
      public function run() {
            if (!defined('CRYPT_BLOWFISH')||!CRYPT_BLOWFISH)
    throw new CHttpException(500,"This application requires that PHP was compiled with Blowfish support for crypt().");
         
     $model=new LoginForm;
          
     if (Yii::app()->request->isAjaxRequest){ 
           if (isset($_POST['LoginForm'])) {  
          $model->attributes=$_POST['LoginForm'];
                               
          if ($model->validate() && $model->login()){
                $array = array("login" => "success");
                              Yii::app()->user->setFlash("success", "Successfully logged in.");
                              $json = json_encode($array);
                              echo $json;
         Yii::app()->end();
   }
   else{
         echo CActiveForm::validate($model);
                              Yii::app()->end();
          }
           } //POST
    
            }
      } 
     
}
  • Create a file named login.php and place it inside components/views with the following contents:
<?php $this->beginWidget('zii.widgets.jui.CJuiDialog',array(
    'id'=>'login-dialog',
    'options'=>array(
        'title'=>'Login',
        'autoOpen'=>false,
    ),
));?>
 
 
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
 'id'=>'user_login_form',
 'enableAjaxValidation'=>false,
  'enableClientValidation'=>true,
                'method' => 'POST',
                'clientOptions'=>array(
                     'validateOnSubmit'=>true,
                     'validateOnChange'=>true,
                     'validateOnType'=>false,
  ),
)); ?>
<h1>
Login</h1>
<p>
Please fill out the following form with your login credentials:</p>
<p class="note">
Fields with <span class="required">*</span> are required.</p>
<div id="login-error-div" class="errorMessage" style="display: none;">
</div>
<div class="row">
  <?php echo $form->labelEx($model,'username'); ?>
  <?php echo $form->textField($model,'username',array("onfocus"=>"$('#login-error-div').hide();")); ?>
  <?php //echo $form->error($model,'username'); ?>
 </div>
<div class="row">
  <?php echo $form->labelEx($model,'password'); ?>
  <?php echo $form->passwordField($model,'password',array("onfocus"=>"$('#login-error-div').hide();")); ?>
  <?php //echo $form->error($model,'password'); ?>
  <p class="hint">
   Hint: You may login with <tt>demo/demo</tt>.
  </p>
</div>
<div class="row rememberMe">
  <?php echo $form->checkBox($model,'rememberMe'); ?>
  <?php echo $form->label($model,'rememberMe'); ?>
  <?php echo $form->error($model,'rememberMe'); ?>
 </div>
<div class="row submit">
   
  <?php echo CHtml::ajaxSubmitButton(
                                'Sign In',
    array('/site/login.GetLogin'),
                                array(  
                'beforeSend' => 'function(){ 
                                             $("#login").attr("disabled",true);
            }',
                                        'complete' => 'function(){ 
                                             $("#user_login_form").each(function(){ this.reset();});
                                             $("#login").attr("disabled",false);
                                        }',
                   'success'=>'function(data){  
                                             var obj = jQuery.parseJSON(data); 
                                            // View login errors!
         // alert(data);
                                             if(obj.login == "success"){
                                         $("#user_login_form").html("<h4>
Login Successful! Please Wait...</h4>
");
                                         parent.location.href = "/";
                                      }
          else{
                                                $("#login-error-div").show();
                                                $("#login-error-div").html("Login failed! Try again.");$("#login-error-div").append("
");
                                             }
           
                                        }' 
    ),
                         array("id"=>"login","class" => "btn btn-primary")      
                ); ?>
         
 </div>
<?php $this->endWidget(); ?>
</div>
<!-- form -->
 
<?php $this->endWidget('zii.widgets.jui.CJuiDialog'); ?>
  • Go to the main layout(blog/protected/views/layouts/main.php) and apply the following changes in the menu:
<div id="mainmenu">
  <?php $this->widget('zii.widgets.CMenu',array(
   'items'=>array(
    array('label'=>'Home', 'url'=>array('post/index')),
    array('label'=>'About', 'url'=>array('site/page', 'view'=>'about')),
    array('label'=>'Contact', 'url'=>array('site/contact')),
     
    //array('label'=>'Login', 'url'=>array('site/login'), 'visible'=>Yii::app()->user->isGuest),
    //array('label'=>'Logout ('.Yii::app()->user->name.')', 'url'=>array('site/logout'), 'visible'=>!Yii::app()->user->isGuest)
   ),
  )); ?>
  <?php $this->widget('loginProvider'); ?>
 </div>
<!-- mainmenu -->

  • Finally, Go to SiteController(/blog/protected/controllers/SiteController) and append 'login.' action inside actions() method. Now, the login action is accessed as '/site/login.GetLogin'
<?php
 
class SiteController extends Controller
{
   ...
public function actions()
 {
  return array(
   // captcha action renders the CAPTCHA image displayed on the contact page
   'captcha'=>array(
    'class'=>'CCaptchaAction',
    'backColor'=>0xFFFFFF,
   ),
   // page action renders "static" pages stored under 'protected/views/site/pages'
   // They can be accessed via: index.php?r=site/page&view=FileName
   'page'=>array(
    'class'=>'CViewAction',
   ),
   'login.' =>  array('class'=>'application.components.loginProvider'),  
  );
 }
       ...
}
3 0
9 followers
Viewed: 38 124 times
Version: 1.1
Category: Tutorials
Written by: pravi
Last updated by: Maxxer
Created on: Sep 14, 2013
Last updated: 4 years ago
Update Article

Revisions

View all history