Commit 02b908bd by Qiang Xue

Fixes #938: added `yii\web\View::renderAjax` and `yii\web\Controller::renderAjax`.

parent 861c2b2f
...@@ -16,6 +16,8 @@ use yii\helpers\Html; ...@@ -16,6 +16,8 @@ use yii\helpers\Html;
* *
* @property string $canonicalUrl The canonical URL of the currently requested page. This property is * @property string $canonicalUrl The canonical URL of the currently requested page. This property is
* read-only. * read-only.
* @property View $view The view object that can be used to render views or view files. This property is
* read-only.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
...@@ -32,6 +34,24 @@ class Controller extends \yii\base\Controller ...@@ -32,6 +34,24 @@ class Controller extends \yii\base\Controller
*/ */
public $actionParams = []; public $actionParams = [];
/**
* Renders a view in response to an AJAX request.
*
* This method is similar to [[renderPartial()]] except that it will inject into
* the rendering result with JS/CSS scripts and files which are registered with the view.
* For this reason, you should use this method instead of [[renderPartial()]] to render
* a view to respond to an AJAX request.
*
* @param string $view the view name. Please refer to [[render()]] on how to specify a view name.
* @param array $params the parameters (name-value pairs) that should be made available in the view.
* @return string the rendering result.
*/
public function renderAjax($view, $params = [])
{
return $this->getView()->renderAjax($view, $params, $this);
}
/** /**
* Binds the parameters to the action. * Binds the parameters to the action.
* This method is invoked by [[Action]] when it begins to run with the given parameters. * This method is invoked by [[Action]] when it begins to run with the given parameters.
......
...@@ -128,6 +128,38 @@ class View extends \yii\base\View ...@@ -128,6 +128,38 @@ class View extends \yii\base\View
private $_assetManager; private $_assetManager;
/** /**
* Renders a view in response to an AJAX request.
*
* This method is similar to [[render()]] except that it will surround the view being rendered
* with the calls of [[beginPage()]], [[head()]], [[beginBody()]], [[endBody()]] and [[endPage()]].
* By doing so, the method is able to inject into the rendering result with JS/CSS scripts and files
* that are registered with the view.
*
* @param string $view the view name. Please refer to [[render()]] on how to specify this parameter.
* @param array $params the parameters (name-value pairs) that will be extracted and made available in the view file.
* @param object $context the context that the view should use for rendering the view. If null,
* existing [[context]] will be used.
* @return string the rendering result
* @see render()
*/
public function renderAjax($view, $params = [], $context = null)
{
$viewFile = $this->findViewFile($view, $context);
ob_start();
ob_implicit_flush(false);
$this->beginPage();
$this->head();
$this->beginBody();
echo $this->renderFile($viewFile, $params, $context);
$this->endBody();
$this->endPage(true);
return ob_get_clean();
}
/**
* Registers the asset manager being used by this view object. * Registers the asset manager being used by this view object.
* @return \yii\web\AssetManager the asset manager. Defaults to the "assetManager" application component. * @return \yii\web\AssetManager the asset manager. Defaults to the "assetManager" application component.
*/ */
...@@ -147,8 +179,11 @@ class View extends \yii\base\View ...@@ -147,8 +179,11 @@ class View extends \yii\base\View
/** /**
* Marks the ending of an HTML page. * Marks the ending of an HTML page.
* @param boolean $ajaxMode whether the view is rendering in AJAX mode.
* If true, the JS scripts registered at [[POS_READY]] and [[POS_LOAD]] positions
* will be rendered at the end of the view like normal scripts.
*/ */
public function endPage() public function endPage($ajaxMode = false)
{ {
$this->trigger(self::EVENT_END_PAGE); $this->trigger(self::EVENT_END_PAGE);
...@@ -159,7 +194,7 @@ class View extends \yii\base\View ...@@ -159,7 +194,7 @@ class View extends \yii\base\View
echo strtr($content, [ echo strtr($content, [
self::PH_HEAD => $this->renderHeadHtml(), self::PH_HEAD => $this->renderHeadHtml(),
self::PH_BODY_BEGIN => $this->renderBodyBeginHtml(), self::PH_BODY_BEGIN => $this->renderBodyBeginHtml(),
self::PH_BODY_END => $this->renderBodyEndHtml(), self::PH_BODY_END => $this->renderBodyEndHtml($ajaxMode),
]); ]);
$this->metaTags = null; $this->metaTags = null;
...@@ -450,25 +485,47 @@ class View extends \yii\base\View ...@@ -450,25 +485,47 @@ class View extends \yii\base\View
/** /**
* Renders the content to be inserted at the end of the body section. * Renders the content to be inserted at the end of the body section.
* The content is rendered using the registered JS code blocks and files. * The content is rendered using the registered JS code blocks and files.
* @param boolean $ajaxMode whether the view is rendering in AJAX mode.
* If true, the JS scripts registered at [[POS_READY]] and [[POS_LOAD]] positions
* will be rendered at the end of the view like normal scripts.
* @return string the rendered content * @return string the rendered content
*/ */
protected function renderBodyEndHtml() protected function renderBodyEndHtml($ajaxMode)
{ {
$lines = []; $lines = [];
if (!empty($this->jsFiles[self::POS_END])) { if (!empty($this->jsFiles[self::POS_END])) {
$lines[] = implode("\n", $this->jsFiles[self::POS_END]); $lines[] = implode("\n", $this->jsFiles[self::POS_END]);
} }
if (!empty($this->js[self::POS_END])) {
$lines[] = Html::script(implode("\n", $this->js[self::POS_END]), ['type' => 'text/javascript']); if ($ajaxMode) {
} $scripts = [];
if (!empty($this->js[self::POS_READY])) { if (!empty($this->js[self::POS_END])) {
$js = "jQuery(document).ready(function(){\n" . implode("\n", $this->js[self::POS_READY]) . "\n});"; $scripts[] = implode("\n", $this->js[self::POS_END]);
$lines[] = Html::script($js, ['type' => 'text/javascript']); }
} if (!empty($this->js[self::POS_READY])) {
if (!empty($this->js[self::POS_LOAD])) { $scripts[] = implode("\n", $this->js[self::POS_READY]);
$js = "jQuery(window).load(function(){\n" . implode("\n", $this->js[self::POS_LOAD]) . "\n});"; }
$lines[] = Html::script($js, ['type' => 'text/javascript']); if (!empty($this->js[self::POS_LOAD])) {
$scripts[] = implode("\n", $this->js[self::POS_LOAD]);
}
if (!empty($scripts)) {
$lines[] = Html::script(implode("\n", $scripts), ['type' => 'text/javascript']);
}
} else {
if (!empty($this->js[self::POS_END])) {
$lines[] = Html::script(implode("\n", $this->js[self::POS_END]), ['type' => 'text/javascript']);
}
if (!empty($this->js[self::POS_READY])) {
$js = "jQuery(document).ready(function(){\n" . implode("\n", $this->js[self::POS_READY]) . "\n});";
$lines[] = Html::script($js, ['type' => 'text/javascript']);
}
if (!empty($this->js[self::POS_LOAD])) {
$js = "jQuery(window).load(function(){\n" . implode("\n", $this->js[self::POS_LOAD]) . "\n});";
$lines[] = Html::script($js, ['type' => 'text/javascript']);
}
} }
return empty($lines) ? '' : implode("\n", $lines); return empty($lines) ? '' : implode("\n", $lines);
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment