You are viewing revision #1 of this wiki article.
This version may not be up to date with the latest version.
You may want to view the differences to the latest version.
The background ¶
The template system in Yii is quite flexible. By default you have three layers of content:
- The Main template holds the header, main navigation and footer
- One or more layout files holds the column setup, sub navigation etc.
- The view files hold the actual page content.
When you load a page, the render method does the following:
- Renders the view file
- Decorates the view with the layout
- Apply the template to the layout.
An AJAX call is normally much more lightweight. If you use renderPartial with the processOutput parameter set to false, the layout and template is never added to the output.
The problem ¶
Sometimes, however, it can be useful to also switch the layout on an AJAX update, without having to load the whole page with all CSS, JS etc.
The solution ¶
The following code snippet from a controller action specifies the view to be rendered and the layout to be applied. For an AJAX update, a renderPartial is used to generate and return the view file. Then a CContentDecorator is created to apply the layout.
switch ($page) {
case 1:
$this->layout = '//layouts/teamPlayers';
$view = 'dashboardPlayers';
break;
case 2:
$this->layout = '//layouts/teamEdit';
$view = 'dashboardEdit';
break;
default:
Yii::app()->end();
}
if (Yii::app()->request->isAjaxRequest) {
$output = $this->renderPartial($view, $params, true, false);
$params['template'] = '';
$ContentDecorator = new CContentDecorator;
$ContentDecorator->view = $this->layout;
$ContentDecorator->data = $params;
$ContentDecorator->processOutput($output);
} else {
$this->render($view, $params);
}
Finally the layout file(s) (located in protected\views\layouts) are modified by replacing the beginContent statement with the following code snippet:
<?php
if (isset($_data_['template'])) {
$this->beginContent($_data_['template']);
} else {
$this->beginContent('//layouts/dashboard');
}
?>
Process the output again.
If you have javascript in the layout file which you are using to decorate the view with, it will not get registered since CContentDecorator > processOutput isn't quite the same as CController > processOutput.
Their is no way to have the output of CContentDecorator > processOutput returned instead of echoed, so I came up with the following solution
// We need to capture the output since CContentDecorator will not // call CController::processOutput(). Javascript needed in the 'sub'layout // will not get registered this way. If we want to use widgets with javascript // it should process $this->layout after including the view. ob_start(); // Render view file as a partial $output = $this->renderPartial($view, $data, true, true); // Not sure if $processOutput should be true here? // Exclude main template $data['template'] = ''; // Decorate with a desired page layout $ContentDecorator = new CContentDecorator; $ContentDecorator->view = $this->layout; $ContentDecorator->data = $data; $ContentDecorator->processOutput($output); $fetch = ob_get_contents(); // Fetch the echo from CContentDecorator ob_end_clean(); // Finally process everything (again?) echo $this->processOutput($fetch); Yii::app()->end();
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.