Now there is no standard good way to embed javascript snippets into views.
Usually these snippets are code that does job specific to each page, like register event handlers.
Yii supports this via CHtml helpers, for example CHtml::ajaxLink, but I never liked this approach, because very soon your view became a mix of HTML and php arrays.
From the first sight helpers seems to be easier way to do ajax requests, but when something doesn’t work as expected it can be really hard to find the reason and solve problem
I think having pure JS code which does the same job is much better and for some time I used something like this:
//here view code, mostly HTML with php snippets to insert variables
//...
//...
//block with JS code
<?php
<?php
Yii::app()->clientScript->registerScript('settings-script', <<<EOD
initForms('myform');
$('.sel-image').live('click',function() {
$('#preview img').attr('src', $(this).find('img').attr('src'));
$(this).parent().addClass('active');;
$(this).parent().siblings().removeClass('active');
$('#SettingsData_stdImg').attr('value', $(this).attr('rel'));
return false;
});
EOD
);
?>
But this way JS code is embedded into the php string and you can forget about code highlight and completions.
So I started to search for better solutions.
One of approaches is to have separate folder where we have JS files for controllers / actions (similar structure to the ‘views’ folder) - http://weavora.com/blog/2011/11/24/yii-framework-an-easy-was-to-split-javascript-from-html/ and (in russian) - http://sergebezborodov.com/yii/loading-js-files-in-yii-framework.html.
I do not like this because js code now is too far from the view and what I want is just to be able to put js code into view (but at the same time I do not want it to be rendered in-place, but it should go into page head or end or jQuery ‘ready’ section).
I looked for solutions for Rails and found many advice like in this question.
For me this Rails solution can be implemented in Yii using clips. In the view file we do:
<?php //$this->beginClip('js-page-end'); ?>
<script type="text/javascript">
alert('my script');
</script>
<?php //$this->endClip(); ?>
And then we render this clip in the layout:
//layout HTML
//...
//render clip with js, if there is no such clip then it will return empty string
<?php $this->renderClip('js-page-end'); ?>
Easy and good solution, but it will not work for the ajax requests where we use renderPartial and in this case layout is not rendered.
And, finally, the solution suggested by Tsunu.
He added a beginScript() and endScript() to the client script component, so code looks like this:
<?php $clientScript = Yii::app()->clientScript; ?>
<?php $clientScript->beginScript('my-script'); ?>
<script type="text/javascript">
alert('my script');
</script>
<?php $clientScript->endScript(); ?>
There is a little hack here - CClientScript automatically wraps script into <script> tags, so in the endScript() Tsunu uses strip_tags($script) before register it using parent registerScript() method.
In conclusion - I think the last solution is close to ideal and it would be good to have support for this in the core CClientScript class.