title: Javascript Development summary: Advanced documentation about writing and customizing javascript within SilverStripe. # Javascript Development The following document is an advanced guide on building rich javascript interactions within the SilverStripe CMS and a list of our best practices for contributing and modifying the core javascript framework. ## ES6 and build tools The remainder of this tutorial is written in [ECMAScript 6](http://es6-features.org/#Constants), or _ES6_ for short. This is the new spec for Javascript (currently ES5) that is as of this writing only partially implmented in modern browsers. Because it doesn't yet enjoy vast native support, it has to be [transpiled](https://www.stevefenton.co.uk/2012/11/compiling-vs-transpiling/) in order to work in a browser. This transpiling can be done using a variety of toolchains, but the basic principle is that a browser-ready, ES5 version of your code is generated in your dev environment as part of your workflow. As stated above, there are many ways to solve the problem of transpiling. The toolchain we use in core SilverStripe modules includes: * [Babel](http://babeljs.io) (ES6 transpiler) * [Webpack](http://webpack.js.org) (Module bundler) __Deprecated:__ The following documentation regarding jQuery, jQueryUI and Entwine applies to legacy code only. If you're developing new functionality in React powered sections please refer to [ReactJS, Redux, and GraphQL](./ReactJS_Redux_and_GraphQL). ## jQuery, jQuery UI and jQuery.entwine: Our libraries of choice We predominantly use [jQuery](http://jquery.com) as our abstraction library for DOM related programming, within the SilverStripe CMS and certain framework aspects. For richer interactions such as drag'n'drop, and more complicated interface elements like tabs or accordions, SilverStripe CMS uses [jQuery UI](http://ui.jquery.com) on top of jQuery. For any custom code developed with jQuery, you have four choices to structure it: Custom jQuery Code, a jQuery Plugin, a jQuery UI Widget, or a `jQuery.entwine` behaviour. We'll detail below where each solution is appropriate. ## Custom jQuery Code jQuery allows you to write complex behavior in a couple of lines of JavaScript. Smaller features which aren't likely to be reused can be custom code without further encapsulation. For example, a button rollover effect doesn't require a full plugin. See "[How jQuery Works](http://docs.jquery.com/How_jQuery_Works)" for a good introduction. You should write all your custom jQuery code in a closure. ```js (function($) { $(document).ready(function(){ // your code here. }) })(jQuery); ``` ## jQuery Plugins A jQuery Plugin is essentially a method call which can act on a collection of DOM elements. It is contained within the `jQuery.fn` namespace, and attaches itself automatically to all jQuery collections. The basics for are outlined in the official [jQuery Plugin Authoring](http://docs.jquery.com/Plugins/Authoring) documentation. There a certain [documented patterns](http://www.learningjquery.com/2007/10/a-plugin-development-pattern) for plugin development, most importantly: * Claim only a single name in the jQuery namespace * Accept an options argument to control plugin behavior * Provide public access to default plugin settings * Provide public access to secondary functions (as applicable) * Keep private functions private * Support the [Metadata Plugin](http://docs.jquery.com/Plugins/Metadata/metadata) Example: A plugin to highlight a collection of elements with a configurable foreground and background colour (abbreviated example from [learningjquery.com](http://www.learningjquery.com/2007/10/a-plugin-development-pattern)). ```js // create closure (function($) { // plugin definition $.fn.hilight = function(options) { // build main options before element iteration var opts = $.extend({}, $.fn.hilight.defaults, options); // iterate and reformat each matched element return this.each(function() { $this = $(this); // build element specific options var o = $.meta ? $.extend({}, opts, $this.data()) : opts; // update element styles $this.css({ backgroundColor: o.background, color: o.foreground }); }); }; // plugin defaults $.fn.hilight.defaults = { foreground: "red", background: "yellow" }; // end of closure })(jQuery); ``` Usage: ```js (function($) { // Highlight all buttons with default colours jQuery(':button').highlight(); // Highlight all buttons with green background jQuery(':button').highlight({background: "green"}); // Set all further highlight() calls to have a green background $.fn.hilight.defaults.background = "green"; })(jQuery); ``` ## jQuery UI Widgets UI Widgets are jQuery Plugins with a bit more structure, targeted towards interactive elements. They require jQuery and the core libraries in jQuery UI, so are generally more heavyweight if jQuery UI isn't already used elsewhere. Main advantages over simpler jQuery plugins are: * Exposing public methods on DOM elements (incl. pseudo-private methods) * Exposing configuration and getters/setters on DOM elements * Constructor/Destructor hooks * Focus management and mouse interaction See the [official developer guide](http://jqueryui.com/docs/Developer_Guide) and other [tutorials](http://bililite.com/blog/understanding-jquery-ui-widgets-a-tutorial/) to get started. Example: Highlighter ```js (function($) { $.widget("ui.myHighlight", { getBlink: function () { return this._getData('blink'); }, setBlink: function (blink) { this._setData('blink', blink); if(blink) this.element.wrapInner(''); else this.element.html(this.element.children().html()); }, _init: function() { // grab the default value and use it this.element.css('background',this.options.background); this.element.css('color',this.options.foreground); this.setBlink(this.options.blink); } }); // For demonstration purposes, this is also possible with jQuery.css() $.ui.myHighlight.getter = "getBlink"; $.ui.myHighlight.defaults = { foreground: "red", background: "yellow", blink: false }; })(jQuery); ``` Usage: ```js (function($) { // call with default options $(':button').myHighlight(); // call with custom options $(':button').myHighlight({background: "green"}); // set defaults for all future instances $.ui.myHighlight.defaults.background = "green"; // Adjust property after initialization $(':button').myHighlight('setBlink', true); // Get property $(':button').myHighlight('getBlink'); })(jQuery); ``` ### jQuery.Entwine jQuery.entwine is a third-party plugin, from its documentation: "A basic desire for jQuery programming is some sort of OO or other organisational method for code. For your consideration, we provide a library for entwineUI style programming. In entwineUI you attach behavioral code to DOM objects. entwine extends this concept beyond what is provided by other libraries to provide a very easy to use system with class like, ploymorphic, namespaced properties." Use jQuery.entwine when your code is likely to be customised by others, for example for most work in the CMS interface. It is also suited for more complex applications beyond a single-purpose plugin. Example: Highlighter ```js (function($) { $(':button').entwine({ Foreground: 'red', Background: 'yellow', highlight: function() { this.css('background', this.getBackground()); this.css('color', this.getForeground()); } }); })(jQuery); ``` Usage: ```js (function($) { // call with default options $(':button').entwine().highlight(); // set options for existing and new instances $(':button').entwine().setBackground('green'); // get property $(':button').entwine().getBackground(); })(jQuery); ``` This is a deliberately simple example, the strength of jQuery.entwine over simple jQuery plugins lies in its public properties, namespacing, as well as its inheritance based on CSS selectors. Please see the [project documentation](http://github.com/hafriedlander/jquery.entwine/tree/master) for more complete examples. When working in the CMS, the CMS includes the jQuery.entwine inspector. Press Ctrl+` to bring down the inspector. You can then click on any element in the CMS to see which entwine methods are bound to any particular element. ## Architecture and Best Practices ### Keep things simple Resist the temptation to build "cathedrals" of complex interrelated components. In general, you can get a lot done in jQuery with a few lines of code. Your jQuery code will normally end up as a series of event handlers applied with `jQuery.on()` or jQuery.entwine, rather than a complex object graph. ### Don't claim global properties Global properties are evil. They are accessible by other scripts, might be overwritten or misused. A popular case is the `$` shortcut in different libraries: in PrototypeJS it stands for `document.getElementByID()`, in jQuery for `jQuery()`. ```js // you can't rely on '$' being defined outside of the closure (function($) { var myPrivateVar; // only available inside the closure // inside here you can use the 'jQuery' object as '$' })(jQuery); ``` You can run `[jQuery.noConflict()](http://docs.jquery.com/Core/jQuery.noConflict)` to avoid namespace clashes. NoConflict mode is enabled by default in the SilverStripe CMS javascript. ### Initialize at document.ready You have to ensure that DOM elements you want to act on are loaded before using them. jQuery provides a wrapper around the `window.onload` and `document.ready` events. ```js // DOM elements might not be available here $(document).ready(function() { // The DOM is fully loaded here }); ``` See [jQuery FAQ: Launching Code on Document Ready](http://docs.jquery.com/How_jQuery_Works#Launching_Code_on_Document_Ready). ### Bind events "live" jQuery supports automatically reapplying event handlers when new DOM elements get inserted, mostly through Ajax calls. This "binding" saves you from reapplying this step manually. Caution: Only applies to certain events, see the [jQuery.on() documentation](http://api.jquery.com/on/#direct-and-delegated-events). Example: Add a 'loading' classname to all pressed buttons ```js // manual binding, only applies to existing elements $('input[[type=submit]]').on('click', function() { $(this).addClass('loading'); }); // binding, applies to any inserted elements as well $('.cms-container').on('click', 'input[[type=submit]]', function() { $(this).addClass('loading'); }); ``` ### Assume Element Collections jQuery is based around collections of DOM elements, the library functions typically handle multiple elements (where it makes sense). Encapsulate your code by nesting your jQuery commands inside a `jQuery().each()` call. ```js $('div.MyGridField').each(function() { // This is the over code for the tr elements inside a GridField. $(this).find('tr').hover( // ... ); }); ``` ### Use plain HTML and jQuery.data() to store data The DOM can make javascript configuration and state-keeping a lot easier, without having to resort to javascript properties and complex object graphs. Example: Simple form change tracking to prevent submission of unchanged data Through CSS properties ```js $('form :input').bind('change', function(e) { $(this.form).addClass('isChanged'); }); $('form').bind('submit', function(e) { if($(this).hasClass('isChanged')) return false; }); ``` Through jQuery.data() ```js $('form :input').bind('change', function(e) { $(this.form).data('isChanged', true); }); $('form').bind('submit', function(e) { alert($(this).data('isChanged')); if($(this).data('isChanged')) return false; }); ``` See [interactive example on jsbin.com](http://jsbin.com/opuva) You can also use the [jQuery.metadata Plugin](http://docs.jquery.com/Plugins/Metadata/metadata) to serialize data into properties of DOM elements. This is useful if you want to encode element-specific data in markup, for example when rendering a form element through the SilverStripe templating engine. Example: Restricted numeric value field ```ss ``` ```js $('.restricted-text').bind('change', function(e) { if( e.target.value < $(this).metadata().min || e.target.value > $(this).metadata().max ) { alert('Invalid value'); return false; } }); ``` See [interactive example on jsbin.com](http://jsbin.com/axafa) ### Return HTML/JSON and HTTPResponse class for AJAX responses Ajax responses will sometimes need to update existing DOM elements, for example refresh a set of search results. Returning plain HTML is generally a good default behaviour, as it allows you to keep template rendering in one place (in SilverStripe PHP code), and is easy to deal with in JavaScript. If you need to process or inspect returned data, consider extracting it from the loaded HTML instead (through id/class attributes, or the jQuery.metadata plugin). For returning status messages, please use the HTTP status-codes. Only return evaluated JavaScript snippets if unavoidable. Most of the time you can just pass data around, and let the clientside react to changes appropriately without telling it directly through JavaScript in AJAX responses. Don't use the [Form](api:SilverStripe\Forms\Form) SilverStripe class, which is built solely around this inflexible concept. Example: Autocomplete input field loading page matches through AJAX Template: ```ss