You are viewing revision #1 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.
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 method
appEdit.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);
Now your PHP and JS code is:
- separated and cleaner
- safer
- easier to read
- more extensible (no more hardcoded labels and urls in JS!)
@nineinchnick
good work. we will try it :-)
JS code examples pls
Hi, good work. But I miss js examples. I think the beginners will make wrong codes from this schema at the first times; and we know that debugging a js code is not easy :)
examples
What do you mean you miss examples? There are examples.
Very good practice
It's a very good practica to keep everything separated.
Recommended.
As @blaces says: A complete example will help beginners to misunderstand what you mean, including the simple example of a view and a JS file.
Or even easier. You can create a github repo with a simple application using an example.
Nice. Very helpful for JS plugin development. Here is a simple example of a plugin
<script> (function( animatemenu, $, undefined ) { // public method animatemenu.animate = function(id,options) { var defaults = { animatePadding: 60, defaultPadding: 10, evenColor: '#ccc', oddColor: '#eee', }; $(id).each(function() { var o =options; var obj = $(this); var items = $("li", obj); $("li:even", obj).css('background-color', o.evenColor); $("li:odd", obj).css('background-color', o.oddColor); items.mouseover(function() { $(this).animate({paddingLeft: o.animatePadding}, 300); }).mouseout(function() { $(this).animate({paddingLeft: o.defaultPadding}, 300); }); }); }; }( window.animatemenu = window.animatemenu || {}, jQuery )); </script> <script type="text/javascript"> $(document).ready(function() { animatemenu.animate('#menu',{animatePadding: 30, defaultPadding:10}) }); </script> <style> body {font-family:arial;font-style:bold} a {color:#666; text-decoration:none} #menu {list-style:none;width:160px;padding-left:10px;} #menu li {margin:0;padding:5px;cursor:hand;cursor:pointer} </style> </head> <body> <ul id="menu"> <li>Home</li> <li>Posts</li> <li>About</li> <li>Contact</li> </ul>
Excellent work!, I would like to share another example of a plugin.
<script> !function(module, $, window, document, undefined) { 'use strict'; var NamePlugin = function() { console.log('NamePlugin'); /*! * Private variables, properties and methods */ // variables var pluginName = 'NamePlugin'; var publicApi = {}; // public api to expose // properties var properties = {defOpt1: 'defOpt1', defOpt2: 'defOpt2'}; // methods var constructor = (function() { console.log(pluginName + ':constructor'); })(); var privateMethod1 = function(message) { console.log(pluginName + ':privateMethod1' + ' ' + (message ? message : '')); }; var privateMethod2 = function() { console.log(pluginName + ':privateMethod2'); }; /*! * Public properties and methods */ // properties publicApi.property1 = 'Publi Property 1'; publicApi.property2 = 'Publi Property 2'; publicApi.defaults = {defProp1: 'defProp1'}; publicApi.settings = {}; // methods publicApi.method1 = function() { console.log(pluginName + ':publicApi.method1'); }; publicApi.method2 = function() { console.log(pluginName + ':publicApi.method2'); }; publicApi.method3 = function() { console.log(pluginName + ':publicApi.method3:expose:privateMethod1'); privateMethod1(); }; publicApi.method4 = function() { console.log(pluginName + ':publicApi.method4:expose:privateMethod2'); privateMethod2(); }; //publicApi.method5 = privateMethod1('from publicApi.method5'); publicApi.init = function(options) { console.log(pluginName + ':publicApi.init'); publicApi.settings = $.extend({}, publicApi.defaults, options); privateMethod1('defaults' + JSON.stringify(publicApi.defaults)); privateMethod1('options' + JSON.stringify(options)); privateMethod1('settings' + JSON.stringify(publicApi.settings)); return publicApi; }; // return the public API (Plugin) to expose return publicApi; }; module.NamePlugin = NamePlugin; }(this, jQuery, window, document); </script> // Passing variables #1 (from view) <script> var myRoute = "<?php echo $this->createUrl('someUrl'); ?>"; var myNamePlugin = new NamePlugin; myNamePlugin.init({name: 'my name', lastName: 'my last name', route: myRoute}); myNamePlugin.method1(); myNamePlugin.method2(); myNamePlugin.method3(); myNamePlugin.method4(); console.log('Get Public Prop1: ' + myNamePlugin.property1); console.log('Get Public Prop2: ' + myNamePlugin.property2); console.log('Get Private Prop: ' + myNamePlugin.pluginName); // undefined because of pluginName is private <script> // Passing variables #2 <?php $options = CJavaScript::encode(array( 'someUrl' => $this->createUrl('someUrl'), 'someLabel' => Yii::t('app', 'someLabel'), )); Yii::app()->clientScript->registerScript(__CLASS__.'#yourPluginName', "var myNamePlugin = new NamePlugin; myNamePlugin.init($options);", CClientScript::POS_READY); ?>
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.