Archive for May, 2008

Use Namespaces to organize your JavaScript code

Wednesday, May 28th, 2008

In today’s modern web applications it is typical to include many libraries, widgets and snippets of code from many different sources. You must be mindful that other developers may be interacting with your code simply by both sets of code being included on the same page. It is not a safe assumption that you have the entire global namespace at your disposal.

Why use namespaces?

The Ext JS forums are an example which utilizes 3 distinctly different sets of scripts from different organizations. We use Ext JS for enhancements, Google Analytics for tracking site usage and the native vBulletin scripts. You can see how all of this code from different sources has been included in the same page. You can also imagine how that there is the potential for a collision as more and more scripts are added.
Code from Different Sources

When looking at Firebug’s Dom tab we can see that hundreds of variables have been created in the window when including these files. Ext consolidates all of its classes into a single namespace of Ext and further organizes its classes into various packages.

Dom Window

When developing your own scripts you should place all of your classes and singletons into namespaces to avoid collisions with other developers code. A namespace as defined by Wikipedia is “an abstract container providing context for the items (names, or technical terms, or words) it holds and allowing disambiguation of items having the same name”

Namespacing is important for developers in order to organize their code and ensure that their code is not overwritten when loaded in the JavaScript interpreter. If another developer defines a variable with the same name your existing definition will be overwritten. The last person to have their code included wins.

Because JavaScript is a functionally scoped language creating a function and/or variable which is not wrapped in another function will result in that variable being created in the global scope (window). To combat this, developers place their classes in Objects.

Namespaces without Ext JS

Without using Ext you could setup namespaces in the following way:

if (!App) App = {};
if (!App.form) App.form = {};
if (!App.data) App.data = {};

Ext.namespace

Ext provides the Ext.namespace method (or the shorthand Ext.ns) which will setup namespaces for you, including checking if the namespace already exists. First define the higher level namespace, then you can define various packages within your namespace. For example to setup a namespace of App and the packages form and data:

/* Ext.namespace will create these objects if they don't already exist */
Ext.namespace('App', 'App.form', 'App.data');
 
/* Now you can define a new class such as SampleForm inside of the App.form package */
App.form.SampleForm = Ext.extend(Ext.form.FormPanel, {
    initComponent: function() {
        /*component configuration code here! */
       App.form.SampleForm.superclass.call(this);
   }
});
 
/* Define MySingleton inside of the App.data package */
App.data.MySingleton = function() {
    return {
        sampleStaticMethod: Ext.emptyFn
    };
}();

Summary

As the client-side JavaScript included in web applications gets larger and more advanced, organization of 3rd party code and your own code becomes increasingly important. Using namespaces will ensure your JavaScript code is safe from other code overwriting it in the global namespace.

Using the standard Panel title config to organize Ext JS form fields

Wednesday, May 14th, 2008

Yesterday while working on our internal support system I had a desire to organize the fields on a form a little better. I didn’t want to use a FieldSet and add full wrapping or another layer of indention in my form code (it’s indented deep enough!) so I decided to give the standard Panel title config attribute a try.

The Panels on my form were using baseCls:’x-plain’ which strips all styling except for required attributes for Ext layouts to function (e.g. overflow:hidden). As expected, the Panel titles looked pretty hideous with no styling. I came up with this simple, short solution and figured I would post it since others might find it useful. Although this application is running on an Ext JS 3.0 dev version, this code will work fine with Ext JS 2.x as well.

Getting started

First, I added some config options to the Panels:

{
    xtype:'panel',
 
    // add a title
    title:'Subscription Details',
 
    // make it collapsible 
    collapsible:true,
 
    // no animation, it looks odd (IMO)        
    animCollapse: false,
 
    // Clicking the title should trigger collapse/expand
    titleCollapse:true,
 
    // No collapse tool button needed
    hideCollapseTool: true,
 
    // generate markup with a custom prefix 'form-group' instead of x-panel or x-plain    
    baseCls:'form-group',
 
    ...

Hideousness

This technically worked, but wasn’t very aesthetically pleasing:

Add in some CSS…

So I added some CSS to my application’s CSS file:

/* add some padding so it spaces nice and relative elements dn't get clipped */
.form-group {
	padding-bottom:5px;
	overflow:hidden;
}
 
/* Simple blue border */
.form-group .form-group-header {
	padding:0;
	border-bottom:1px solid #c3daf9;
}
 
/* Position the text element so it appears over the border added above */
.form-group .form-group-header-text {
	font-size:11px;
	font-family:tahoma,arial,sans-serif;
	line-height:13px;
	text-transform:uppercase;
	position:relative;
	left:5px;
	top:5px;
	padding:1px 5px 1px 20px;
	color:#4e79b2;
	background:#fff url(../images/form-collapse-icon.gif) no-repeat 2px 0;
}
 
/* Copied from x-plain (for IE + layouts to work) */
.form-group-body {
    overflow:hidden;
}
 
/* Copied from x-plain (for IE + layouts to work) */
.form-group-bwrap {
    overflow:hidden;
    zoom:1;
}
 
/* Change the toggle icon when collapsed */
.x-panel-collapsed .form-group-header-text {
	background-position: 2px -15px;
}

Extellent!

I’m not a designer, but I was pretty happy with the result:

Reusable

I personally can’t handle setting all those config options on every form group I create and I really need the code I am working with to stay clean, so I created this simple extension:

Ext.ux.FormGroup = Ext.extend(Ext.Panel, {
	collapsible:true,
	animCollapse: false,
	titleCollapse:true,
	hideCollapseTool: true,
	baseCls:'form-group'
});
Ext.reg('formgroup', Ext.ux.FormGroup);

So now when I want to add a form group, it’s as simple as using a different xtype and setting a title:

{
    xtype:'formgroup',
    title:'Subscription Details',
    ...

Resources

The CSS sprite image used for the expand/collapse icon in the CSS above is available here.