Adding JavaScript to a Page in Yii

August 18, 2014
The Yii Book If you like my writing on the Yii framework, you'll love "The Yii Book"!

The first thing you’ll need to know to use JavaScript and jQuery in Yii is how to add JavaScript to a Web page. As with any standard Web page, there are two primary options:

  • Link to an external file that contains the JavaScript code
  • Place the JavaScript code directly in the page using SCRIPT tags

Just as I assume you’re already comfortable with JavaScript, I’ll also assume you know the arguments for and against both approaches. (Technically, there’s a third option: place the JavaScript inline within an HTML tag. This is not a recommended approach in modern Web sites, however, and I won’t demonstrate it here.)

This is an excerpt from Chapter 12, “JavaScript and jQuery,” of “The Yii Book“.

Linking to JavaScript Files

External JavaScript files are linked to a page using the SCRIPT tag:

<script src="/path/to/file.js"></script>

The contemporary approach is to link external files at the end of the HTML BODY, although some JavaScript libraries must be included in the HEAD.

If you need to include a JavaScript file on every page of your site, an option is to just add the reference to your layout file:

<script src="<?php echo Yii::app()->request->baseUrl; ?>/path/to/file.js"></script>

Do be certain to use an absolute reference to the file, for reasons explained in Chapter 6, “Working with Views.”

Alternatively, you can use Yii’s CHtml::scriptFile() method to create the entire HTML tag:

<?php echo CHtml::scriptFile(Yii::app()->request->baseUrl . "/path/to/file.js");
?>

The end result is the same.

Sometimes, you’ll have external JavaScript files that should only be included on specific pages. In theory, you could just add the appropriate SCRIPT tag to the corresponding view files, but that’s less than ideal for a couple of reasons. For one, the final page will end up with SCRIPT tags in the middle of the page BODY, which is sloppy. Another reasons why you don’t want to take this approach is that it gives you no vehicle for putting the script in the HTML HEAD, should that be necessary.

The better way to add external files to a page from within the view file is to use Yii’s “clientScript” component, and its registerScriptFile() method in particular:

# protected/views/foo/bar.php
<?php Yii::app()->clientScript->registerScriptFile("/path/to/file.js"); ?>

The “clientScript” application component manages JavaScript and CSS resources used by a site. By calling that line anywhere in a view file (or a controller), Yii will automatically include a link to the named JavaScript file in the complete rendered HTML. Further, if, for whatever reason, you register the same JavaScript file more than once, Yii will still only create a single SCRIPT tag for that file.

By default, Yii will link the registered script in the HTML HEAD. To change the destination, add a second argument to registerScriptFile(). This argument should be a constant that indicates the proper position in the HTML page for the JavaScript file reference:

  • CClientScript::POS_HEAD, in the HEAD before the TITLE (the default)
  • CClientScript::POS_BEGIN, at the beginning of the BODY
  • CClientScript::POS_END, at the end of the BODY

To have the SCRIPT tag added at the end of the body, you would do this:

# protected/views/foo/bar.php
<?php Yii::app()->clientScript->registerScriptFile("/path/to/file.js", CClientScript::POS_END); ?>

Linking jQuery

The previous section explained how to link external JavaScript files from a Web page. There’s a subset of external JavaScript files that are treated differently, however. I’m referring to JavaScript files that come with the Yii framework, such as the jQuery library.

To incorporate jQuery into a Web page, invoke the registerCoreScript() method, providing it with the value “jquery”:

<?php Yii::app()->clientScript->registerCoreScript("jquery"); ?>

That line results in the jQuery library being linked to the page via a SCRIPT tag. The jQuery library is referenced within the Web directory’s assets folder. Copies of the library will be placed in that folder by Yii’s assets manager.

By default, registerCoreScript() will place SCRIPT tags within the HTML HEAD. To have Yii place the tags elsewhere, change the coreScriptPosition attribute value to one of the constants already named:

<?php
Yii::app()->clientScript->coreScriptPosition = CClientScript::POS_END;
Yii::app()->clientScript->registerCoreScript("jquery");
?>

You can also globally change this setting in your primary configuration file (by assigning a value to the “coreScriptPosition” index of the “clientScript” component).

Some pages, like those that use certain widgets or that have Ajax form validation enabled, will already include jQuery. Fortunately, you don’t have to worry about possible duplication, as the Yii assets manager will only incorporate the library once.

If you’re curious as to what other core scripts are available, check out the web/js/packages.php file found in your Yii framework directory. As of this writing, some of the core scripts are:

  • jquery
  • yii, a Yii extension of the jQuery library
  • yiiactiveform, which provides code for client-side form validation
  • jquery.ui
  • cookie, for cookie management
  • history, for client-side history management

This means, for example, to incorporate the jQuery User Interface library, you would do this:

<?php
Yii::app()->clientScript->registerCoreScript("jquery.ui");
?>

For all of the options, and details on the associated scripts, see the web/js/sources directory (within the Yii framework folder).

Adding JavaScript Code

When you have short snippets of JavaScript code, or when the code only pertains to a single file, it’s common to write that code directly between the HTML SCRIPT tags. Again, you could do this in your view files:

<script>
/* Actual JavaScript code. */
</script>

You could also use the Yii CHtml::script() method to create the SCRIPT tag for you:

<?php echo CHtml::script("/* Actual JavaScript code. */"); ?>

You could add SCRIPT tags in either of those ways, but there’s a better approach: the “clientScript” component’s registerScript() method. This is the companion to registerScriptFile(), but instead of linking to an external JavaScript file, it’s used to add JavaScript code directly to the page.

The method’s first argument is a unique identifier you should give to the code snippet. The second is the JavaScript code itself. This code is generated by Gii on the “admin” view pages:

# protected/views/page/admin.php
<?php
Yii::app()->clientScript->registerScript("search", "$(".search-button").click(function(){
    $(".search-form").toggle();
    return false;
});
$(".search-form form").submit(function(){
    $.fn.yiiGridView.update("post-gridæ, {
        data: $(this).serialize()
    });
    return false;
});
");
?>

The first bit of JavaScript (lines 4-7), shows and hides the advanced search form that can appear above the grid. The form’s visibility is toggled when the user clicks on the search button. The second bit invokes the yiiGridView.update() method when the search form is submitted. Both sections use jQuery.

As you can see in that example, the combination of PHP and JavaScript can easily lead to syntax errors. You should use one set of quotation types to encapsulate the JavaScript (passed to registerScript()) and another type within the JavaScript. Also be certain to terminate JavaScript commands with semicolons, and terminate the PHP command, too. If the JavaScript you write doesn’t work, start by confirming that the resulting JavaScript code (in the browser’s source) is syntactically correct.

One of the benefits of providing a unique identifier is that the “clientScript” component will manage the code bits so that even if the same code (by identifier) is registered multiple times, it will still only be placed on the page once.

As with registerScriptFile(), registerScript() takes a final argument to indicate where, in the HTML page, the JavaScript should be added:

  • CClientScript::POS_HEAD, in the HEAD before the TITLE (the default)
  • CClientScript::POS_BEGIN, at the beginning of the BODY.
  • CClientScript::POS_END, at the end of the BODY.
  • CClientScript::POS_LOAD, within a window.onload event handler
  • CClientScript::POS_READY, within a jQuery “ready” event handler

The two additional options are necessary because of the way the browser loads the DOM. If you are using jQuery and you want to execute some JavaScript when the document is ready, use CClientScript::POS_READY. It’s slightly faster than the standard JavaScript window.onload option. If you’re not using jQuery, then use CClientScript::POS_LOAD.