Yii 1.1: Reliable Alternative For Yii::app()->request->isAjaxRequest AND Adding Data To Ajax Form With JS

11 followers

In this How-To I'll show you:

1.) A reliable alternative to Yii::app()->request->isAjaxRequest (because it doesn't work for everybody and it's not reliable)

2.) How to add extra data to an ajax-request without setting a hiddenField in your form, only using javascript, before sending the form.

Here you can read more about why 'isAjaxRequest' isn't reliable: http://www.yiiframework.com/forum/index.php?/topic/4945-yiiapp-request-isajaxrequest/

The main idea is adding a parameter to our request which tells us if the current request is an ajax-request or not. So if you work with an ajax form, you would for example add a hiddenField named 'isAjaxRequest' and set the value to '1'. But this won't work, if you have a form which can be sent with both, ajax- and usual post-request for users having disabled javascript. So the solution is adding a parameter 'isAjaxRequest' to our form with javascript, before sending it, instead of adding a hiddenField.

After building our form, we add a submitButton like this (in this case for searching users):

<?php 
// Sorry for bad shifting, it's not my fault ...
 
echo CHtml::ajaxSubmitButton('Search', CHtml::normalizeUrl(array('user/search')), 
     array(
       'data'=>'js:jQuery(this).parents("form").serialize()+"&isAjaxRequest=1"',               
       'success'=>
                  'function(data){
                        $("#searchResult").html(data);
                        $("#searchResult").show();
                        return false;
                   }'    
 
     ), 
     array(
        'id'=>'ajaxSubmit', 
        'name'=>'ajaxSubmit'
     )); 
?>

jQuery(this).parents("form").serialize() is what Yii's ajaxSubmitButton would usually do, if you had not set the 'data' parameter. Now we add +"&isAjaxRequest=1" to set a parameter 'isAjaxRequest' with value '1' to our ajax-request. So this is how to add parameters to ajax-request with javascript. You can add as many parameters as you want like this. js:jQuery(this).parents("form").serialize()+"&isAjaxRequest=1&parameter1=value1&parameter2=value2"

By setting the parameter 'isAjaxRequest' we can filter our ajax request in our controller-action like follows:

public function actionSearch() {
      if($_POST['isAjaxRequest']=='1') {
        // your business logic for ajax-request
        // usually with renderPartial at the end, in order to render a partial view
        $this->renderPartial('ajaxSearchResult', array('param1'=>'value1'), false, true);
      }
      else {
     // your business logic for non-ajax-request
         // usually with render at the end, in order to render a whole view with your layout
         $this->render('searchResult',array(
        'param1'=>'value1',
     ));
      }
  }

Very simple, but works ...

Total 2 comments

#16514 report it
MKay at 2014/03/01 09:03am
Alternative

One thing to note is that Yii internally uses getIsAjaxRequest for some things, like CWebUser's loginRequired method. So IMHO it is a good idea to make getIsAjaxRequest work with the GET-parameter-method mentioned above. So you can still use getIsAjaxRequest in your own code.

I created a behavior that checks on each request if the isAjaxRequest-GET-parameter is set. If so, the HTTP_X_REQUESTED_WITH header will be set manually (if not already done). So getIsAjaxRequest will work like expected. Place this file in your component folder:

/**
 * Class AjaxRequestBehavior
 *
 * Yii's CHttpRequest->getIsAjaxRequest method uses only the HTTP_X_REQUESTED_WITH header
 * to check if the request was made using Ajax. But this header may be removed by some
 * Webservers or proxy-servers. So one should always include a GET-parameter 'isAjaxRequest' for Ajax-
 * requests to indicate that the request was made using Ajax.
 *
 * This Behavior checks whether the GET-parameter exists and if so it sets the
 * HTTP_X_REQUESTED_WITH header manually. Thus the getIsAjaxRequest method will be more
 * reliable and internal Yii functions will benefit from this, for example CWebUser->loginRequired.
 */
class AjaxRequestBehavior extends CBehavior
{
    public function attach($owner)
    {
        $owner->attachEventHandler('onBeginRequest', array($this, 'ensureXHRHeaderIfAjaxRequest'));
    }
 
    public function ensureXHRHeaderIfAjaxRequest($event)
    {
        if (isset($_GET['isAjaxRequest']) && (!isset($_SERVER['HTTP_X_REQUESTED_WITH']) || $_SERVER['HTTP_X_REQUESTED_WITH']!=='XMLHttpRequest')) {
            $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
        }
    }
}

Then simply add this behavior to your Application using the config/main.php:

...
    'behaviors' => array(
        'application.components.AjaxRequestBehavior'
    ),
...
#9563 report it
Jose H. Milán at 2012/08/23 06:27am
Really usefull

Very simple, beautiful and usefull.

I prefer to use links, could I use ajaxLink that way? (I have tested it and works fine)

echo CHtml::ajaxLink('Search', CHtml::normalizeUrl(array('user/search')), 
     array(
       'type'=>'POST',
       'data'=>'js:jQuery(this).parents("form").serialize()+"&isAjaxRequest=1"',               
       'success'=>
                  'function(data){
                        $("#searchResult").html(data);
                        $("#searchResult").show();
                        return false;
                   }'    
 
     ), 
     array(
        'id'=>'ajaxSubmit', 
        'name'=>'ajaxSubmit'
     ));

Thank you.

Leave a comment

Please to leave your comment.

Write new article