Yii2: Exclude assets from rendering

Created on 30 Jul 2014  路  14Comments  路  Source: yiisoft/yii2

Hello.
I have this case:
On page1 there is Bootstrap Modal which content is loading via ajax from page2. To not include header and footer into page2 I'm using renderAjax in page2 controller. But I need to exclude some assets which are loading automatically: for example, Bootstrap offset. I have two reasons for this:

  1. These assets are already loaded in parent document (page1) and I don't need unnecessary network requests for these CSS and JS files.
  2. On page1 I'm using my own css file which overrides some Bootstrap styles. And when modal content is loaded, styles of page1 are overriding by bootstrap.css.

So I'm looking for a way to exclude specified assets from rendering (by renderAjax, as minimum).

P.S. renderPartial is not a solution, beacuse in case of using it inline JS registered by widgets are missing.

Most helpful comment

Insert this code before render ))
Yii::$app->assetManager->bundles = [
'yii\bootstrap\BootstrapPluginAsset' => false,
'yii\bootstrap\BootstrapAsset' => false,
'yii\web\JqueryAsset' => false,
];

All 14 comments

I suppose it could be better if we could have an option when using renderAjax to specifically isolate the following:

  • Asset registration via asset bundle i.e. AssetBundle::register($view).
  • Inline scripts/ or additional files registered via registerJs, registerCss, registerJsFile, registerCssFile methods.

Then we could control registration of asset bundles separately and inline scripts/additional files separately in renderAjax... in such complex view rendering process.

you can unregister assets by using ie.:

yii\web\View Object
(
    [assetBundles] => Array
        (
        )
)

-->
unset($this->assetBundles['yii\web\JqueryAsset']);


Where? In controller and view itself assetBundles is not filled yet. All assets will be defined and filled only inside rendering methods.

by using a ajax-layout for the renderAjax

I guess you could also try to use Events for this matter. Perhabs View::EVENT_AFTER_RENDER and then use \Yii::$app->view

@dynasource yes, your suggestion about ajax layout is working. I'm calling render instead of renderAjax and using special layout with such code:

<?php
unset($this->assetBundles['yii\bootstrap\BootstrapAsset']);
unset($this->assetBundles['yii\web\JqueryAsset']);
unset($this->assetBundles['yii\web\YiiAsset']);
unset($this->assetBundles['kartik\widgets\Select2Asset']);
unset($this->assetBundles['kartik\widgets\WidgetAsset']);
?>
<?php $this->beginPage() ?>
<?php $this->head() ?>
<?php $this->beginBody() ?>
<?= $content ?>
<?php $this->endBody() ?>
<?php $this->endPage() ?>

(as universal solution I can pass an array of bundles to unset from controller action). Thanks!
But Kartik's idea is much better than this workaround. Let's wait for Yii devs to look on this.

Youre welcome.
I do think passing data around would make the framework complex. The View component is accessible in the application which would enable one to unset assetBundles easily with ie. Events.

@RomeroMsk yes its register - corrected it.

@dynasource if you try to access assetBundles from controller action before rendering you'll see it's empty (because all assets will be included inside rendering method). I didn't try event (honestly, I don't know how to attach event listener to view from controller before rendering it by view name), but I think it also won't work.

Romero, I didnt say that before rendering worked. EVENT_AFTER_RENDER is the one you need. To help you out with an example. Put this anywhere in your code:

\yii\base\Event::on(\yii\web\View::className(), \yii\web\View::EVENT_AFTER_RENDER, function ($e) {
  $e->sender->assetBundles = [];
});            

@dynasource it's magic :) I used your example and it's working. Now I don't need special layout, I'm just attaching event listener with unsets and calling renderAjax. Thank you again, this is the way I've looking for!
I leave this issue opened to see devs comments about this case.

If your ajax response has some <script src=""></script> tags that already exist on the page Yii should stop them from being requested again.
Unfortunately it doesn't work for CSS.

true. Currently, I am using a custom implementation to prevent 'similar' scripts being included. To give you a direction:

    var jsFiles = <?php echo \yii\helpers\Json::encode(($this->context->jsFiles[View::POS_END]))?>;
    var jsFilesDone = $('script[src]');   
    $.each( jsFiles, function( url,script ) {    
        var matchedScripts = jsFilesDone.filter(function () {
            return this.src === 'http://' + document.location.host + url;
        })    
        if (!matchedScripts.length) jsFilesTodo.push(url); 
    });

Insert this code before render ))
Yii::$app->assetManager->bundles = [
'yii\bootstrap\BootstrapPluginAsset' => false,
'yii\bootstrap\BootstrapAsset' => false,
'yii\web\JqueryAsset' => false,
];

Was this page helpful?
0 / 5 - 0 ratings