Tuesday, July 9, 2013

Yii: Loading a block through AJAX

Nowadays, it's common when a part of a page is loaded asynchronously. Let's implement the quotes box which will display random quotes and will have the "Next quote" link to show the next one.

Getting ready

  • Create a fresh Yii application using yiic webapp as described in the official guide
  • Configure application to use clean URLs

How to do it...

Carry out the following steps:
  1. Create a new controller named protected/controllers/QuoteController.php as follows:
  2. quotes[array_rand($this->quotes, 1)];
            }
            
            function actionIndex()
            {
                $this->render('index', array(
                    'quote' => $this->getRandomQuote()
                ));
            }
            function actionGetQuote()
            {
                $this->renderPartial('_quote', array(
                    'quote' => $this->getRandomQuote(),
                ));
            }
    }

  3. We will require two views. The first is protected/views/quote/index.php:

  4. Quote of the day

    renderPartial('_quote', array( 'quote' => $quote, ))?>
    '#quote-of-the-day'))?> }
    The second view named protected/views/quote/_quote.php is as follows:
     
    &ldquo;<?php echo $quote[0]?>&rdquo;, <?php echo $quote[1]?>
    
  5. That is it. Now, try to access your quote controller and click on the Next quote link, as shown in the following screenshot:

How is works...

First, we define a list of quotes in the controller's private property $quotes and create a method to get a random quote. In a real application, you will probably get a quote from a database using DAO or an active record.
Then, we define a view for the index action and _quote which is used in the getQuote action that renders it without layout and the index view as a partial. In the index action, we use CHtml::ajaxLink to create a link which makes a request to the getQuote action and updates the HTML element with the ID of quote-of-the-day. This is done with a response CHtml::ajaxLink that generates the following code in the resulting HTML page (reformatted):
 

As jQuery is being used, Yii includes it in the page automatically and does it only once, no matter how many times we are using it.

There's more...

If you want to customize the success callback, then you can do this by setting it through a third parameter as follows:
 
 'js:function(data){
   alert(data);
   }'))?>
In some cases, it is not desirable to allow a non-AJAX access to the getQuote action. There are two ways through which we can limit its usage to AJAX-only. First, you can use the built-in ajaxOnly filter as follows:
class QuoteController extends Controller
{
  function filters()
  {
     return array(
       'ajaxOnly + getQuote',
     );
  }
...
After adding this, ones who try to use the getQuote action directly will get an HTTP error: 400 Bad Request. The second way is to detect if request is made through AJAX with a special request method. For example, if we want to show the standard 404 "Not found" page, we can do this as follows:
function actionGetQuote()
{
  if(!Yii::app()->request->isAjaxRequest)
    throw new CHttpException(404);
  $this->renderPartial('_quote', array(
    'quote' => $this->getRandomQuote(),
  ));
}
Similarly, we can use one action to serve both AJAX and non-AJAX responses:
function actionGetQuote()
{
  $quote = $this->getRandomQuote();
  if(Yii::app()->request->isAjaxRequest)
  {
    $this->renderPartial('_quote', array(
      'quote' => $quote,
    ));
  }
  else
  {
    $this->render('index', array(
      'quote' => $quote,
    ));
  }
}

Prevent including a bundled jQuery

Sometimes, you need to suppress including a bundled jQuery. For example, if your project code relies on version specific functionality. To achieve this, you need to configure a clientScript application component using protected/config/main.php as follows:
return array(
  // …
  // application components
  'components'=>array(
    // …
    'clientScript' => array(
    'scriptMap' => array(
      'jquery.js'=>false,
      'jquery.min.js'=>false,
    ),
  ),
),

// …
);

Further reading

  • http://api.jquery.com/
  • http://docs.jquery.com/Ajax/jQuery.ajax#options
  • http://www.yiiframework.com/doc/api/CHtml#ajax-detail
  • http://www.yiiframework.com/doc/api/CHtml#ajaxButton-detail
  • http://www.yiiframework.com/doc/api/CHtml#ajaxSubmitButtondetail
  • http://www.yiiframework.com/doc/api/CHtml#ajaxLink-detail

0 comments:

Post a Comment