Yii2: Order position for resources in yii\web\View

Created on 26 Nov 2013  路  20Comments  路  Source: yiisoft/yii2

What about to add in registerMetaTag(), registerLinkTag(), registerCss(), registerCssFile(), registerJs(), registerJsFile() additional argument to manage the order of the registered resources?
For example:

        public function registerJsFile($url, $options = [], $key = null, $internalPosition=10)
        {
                $position = isset($options['position']) ? $options['position'] : self::POS_END;
                unset($options['position']);
                $key = $key ?: $url;
                $this->jsFiles[$position][$key]['resource'] = Html::jsFile($url, $options);
                $internalPosition=(int)$internalPosition;
                $this->jsFiles[$position][$key]['internalPosition'] = $internalPosition;
        }

Later in rendered methods like renderHeadHtml() the resources are ordered by internal position. We can manage what resource should be the first in html code and what resource should be the last.

under discussion

All 20 comments

+1.

And this sorting should be among both internal js code and external JS files. At the current implementation we inlude at first all js files and after them - inline scripts.
But It might come in handy to print some inline js code between external script tags.

And maybe we need to do this only for js (not css, meta...) ?

It will be handy to any method, I think.

If sorting is both for js-files and inline scripts together then it is more complicated and confused.

Will not support this. For js/css files, you should use dependency and asset bundles to determine their relative orders. For inline js/css code, if order is really important, you can directly manipulate View::css and View::js to adjust their relative order.

There is one moment.
In this code the event should be triggerred after bundles have put their resources into View object.
Now it is triggered before so I cannot adjust the final set of css and js resources.

User case:

  1. It is a basic application with AppAsset::register($this); in the main layout. It would include jquery.js.
  2. I have some page with it's about.php view file:
/**
 * @var yii\web\View $this
 */
$this->registerJsFile('@web/js/some1.js', [], 'abcdef');
?>
<h1>learn/about</h1>

<p>
    You may change the content of this page by modifying
    the file <code><?php echo __FILE__; ?></code>.
</p>

This would result to this html:

<script src="/web/js/some1.js"></script>
<script src="/web/assets/b3ce897/jquery.js"></script>

But I want /some1.js to be after /jquery.js. And both in the POS_END.
IF to move this foreach to the beginning of the endPage method I could achieve what I want with the next code in the about.php:

$this->registerJsFile('@web/js/some1.js', [], 'abcdef');
$this->on($this::EVENT_END_PAGE, function ($event){
    $view = \yii::$app->getView();
    $script = $view->jsFiles[$view::POS_END]['abcdef'];
    unset($view->jsFiles[$view::POS_END]['abcdef']);
    $view->jsFiles[$view::POS_END][] = $script;
});

You should use asset bundle and rely on dependency to make the order right.

I understand about how to achieve this with a new bundle.
But:
1) For a content manager it is easier to add just a js file and add some snippet to the page. Creating a bundle is not the point for a non programmer.
2) Right now it looks strange why I have an ability to use $this->registerJsFile but it wont do any good.
If I have jquery library at my site then logically all my custom js files would be with jQuery code.
But I can't make this file work as it is proposed in the API, because it is included before the library itself.
The only point is to move a jquery bundle to a POS_HEAD section.
3) Maybe I am missing something but I don't see why not to move the foreach loop before triggering the event. (it looks to me like a 1+2 = 2+1 case).

1) For a content manager it is easier to add just a js file and add some snippet to the page. Creating a bundle is not the point for a non programmer.

The approach you show here isn't any easier than using asset bundles. If you have a systematic way of using asset bundles (e.g. define an asset bundle for every view), then it's much easier to modify the corresponding asset bundle.

Right now it looks strange why I have an ability to use $this->registerJsFile but it wont do any good.
If I have jquery library at my site then logically all my custom js files would be with jQuery code.

As said in the API, you should use asset bundle if the file being registered depends on something else. In fact, originally we wanted to hide this API. But we thought this API might be useful by some advanced asset handling extensions. So we exposed it.

Maybe I am missing something but I don't see why not to move the foreach loop before triggering the event. (it looks to me like a 1+2 = 2+1 case).

What if someone wants to register additional asset bundles in this event?

What if someone wants to register additional asset bundles in this event?

I have not thought about that. All right then. Thank you for an explanation.

Hi i sthere a way to give the css files depends ?

<link href="/yii-press/frontend/web/assets/2dd152ef/css/tasktree.css" rel="stylesheet">
<link href="/yii-press/frontend/web/dist/css/site.css" rel="stylesheet">
<link href="/yii-press/frontend/web/dist/css/navbar.css" rel="stylesheet">

i build a module and this css have to be after the site.css but i don't configure it out to order the Asset
the asset file
https://bitbucket.org/DrMabuse/nestedmenu/src/e6e710337f5115c4bb087e71b6cdf156247a6a4a/src/nestedmenu/assets/NestedAssets.php?at=master
greetz

ok and how to use this in my AssetBundle
/**
* @var array the options that will be passed to [[yiiwebView::registerCssFile()]]
* when registering the CSS files in this bundle.
*/
public $cssOptions = [];

didn't find example and thx for your Help

Hey qiangxue,
i read it now ,my Question i added

 public $cssOptions= [
    'frontend\assets\AppAsset::className()'
];

this one push the file after my site.css from my frontend AppAsset but what is more random as intended ? make no sense too

@brewing

i added
...
this one push the file after my site.css

It is hard to belive.

@qiangxue, good thinking about depends feature for resources. Thanks.

@brewing no, your usage about cssOptions is incorrect. Please check out this: https://github.com/yiisoft/yii2/blob/master/docs/guide/assets.md

Sorry but i dont understand what do you wannt to say me.
Assetbundle is wrong to add css only for scss and less ?
i have to use $this->registerCssFile ? but how to get out the generated assets path from my module ? my alias is the sourcePath not the Url. The Side you paste cssOptions are no example howto whatever.

No, I was suggesting you read through the basic tutorial about asset bundle before trying to guess how to use it. You should use depends not cssOptions to specify the dependency.

ok i get it thx i missunderstand it, i always mean dependency only for jsFiles but you are right thx .

/**
 * @var array
 */
public $depends = [
    'yii\web\JqueryAsset',
    'yii\web\YiiAsset',
    'yii\bootstrap\BootstrapAsset',
    'yii\jui\SortableAsset'
];

but next problem it would be to use this because frontend not in basic app exist. But i will add on my module params and merge it.

I need to necro this a bit.

I actually just ran into the ordering of INLINE resources today.

My scenario is that I have socket.io doing some crazy stuff on my page producing a chat app within my PHP page, but then I also have it doing something with my layout, essentially handling notifications.

So socket.io is having to be used in two different places, inner view and layout. In PHP the inner comes before the outer but in browser rendering outer comes first so I have to find a way of making sure that the outer has access to socket.io by ensuring that:

var socket = io.connect('', {query: 'userid=" . Yii::$app->getUser()->getId() . "'});

Always comes first straight after the inclusion of files. Currently there is no good way of doing this

in fact it is easy, for example, when you want to register some1.js after jquery, you only use the following script to register your some1.js
$this->registerJsFile('@web/js/some1.js', ["depends" => [yii\web\JqueryAsset::className()]], 'abcdef');
Then all are don

Was this page helpful?
0 / 5 - 0 ratings