Clean JavaScript code in your views

You are viewing revision #2 of this wiki article.
This version may not be up to date with the latest version.
You may want to view the differences to the latest version or see the changes made in this revision.

« previous (#1)next (#3) »

This tutorial presents a way of separating JS code from views and passing to it values from PHP.

Yii provides two handful ways of keeping JavaScript code close to the widgets and other elements they interact with:

  • strings prefixed with 'js:'
  • CClientScript.registerScript method

Quickly, small snippets of JavaScript code turn into big ugly strings filled with PHP variables and without proper syntax higlighting.

This tutorial shows a method of organizing JavaScript code and integrating it with a PHP backend.

jQuery plugin template

This template for building JavaScript plugins is proposed by jQuery:

[javascript]
(function( yourPluginName, $, undefined ) {
   // public method
   yourPluginName.someCallback = function() {
   };
}( window.yourPluginName = window.yourPluginName || {}, jQuery ));

This defines a function that is immediately called and passed two arguments:

  • a reference to window.yourPluginName
  • the jQuery object

This allows to extend the global yourPluginName object by adding methods and properties to it, keeping them all in one scope.

Now you can place your bulky JS code from your views inside such plugin and use them as:

[javascript]
yourPluginName.someCallback();

Put that template in a .js file, for example protected/components/assets/yourPluginName.js.

Then register it in your action or view:

$path = Yii::app()->assetManager->publish(Yii::getPathOfAlias('application.components.assets'));
Yii::app()->clientScript->registerScriptFile($path.'/yourPluginName.js');

Namespaced code

By putting all your code in such plugin you keep them in a limited scope and thus create a namespace for it. That helps avoiding name conflicts and keeps your code cleaner.

Another important feature is that such plugin can be registered many times. Sometimes that happen when you load an action through AJAX on a page that already registered that script.

This also allows extending if further, adding more functions.

Also, since there actually is a limited scope, strict mode can be enabled:

[javascript]
(function( yourPluginName, $, undefined ) {
    "use strict";
    // ... more code
}( window.yourPluginName = window.yourPluginName || {}, jQuery ));

This helps to detect browser-specific issues early in the development that is done using the developer's favourite browser, not the ones that clients are using.

Passing variables from PHP

Very often JavaScript code needs data from PHP, like URLs, ids, translated labels and other configuration.

They can be stored inside the plugin by adding a private variable and an init() function:

[javascript]
(function( yourPluginName, $, undefined ) {
    // guard to detect browser-specific issues early in development
    "use strict";
    // private var
    var _settings;
    // public var
    yourPluginName.someProperty = 'default value';

    // public method
    yourPluginName.init = function(settings) {
        _settings = $.extend({}, settings);
    }
}( window.yourPluginName = window.yourPluginName || {}, jQuery ));

Now after registering the script file add a call to the init() function on document load:

$options = CJavaScript::encode(array(
   'someUrl' => $this->createUrl('someUrl'),
   'someLabel' => Yii::t('app', 'someLabel'),
));
Yii::app()->clientScript->registerScript(__CLASS__.'#yourPluginName', "yourPluginName.init($options);", CClientScript::POS_READY);

The '_settings' var is private and can be only referenced inside functions defined in yourPluginName;

Now your PHP and JS code is:

  • separated and cleaner
  • safer
  • easier to read
  • more extensible (no more hardcoded labels and urls in JS!)