Most of our development work in the Extjs space entails creating new apps from scratch. Having worked in this capacity as “cleaners” for quite some time now, we’ve noticed a common set of ill-advised coding practices that tend to pop up rather often in the apps we’re investigating. Based on a review of our work over the last few years, I came up with this list of development practices we recommend you avoid in your Ext JS apps.
1. Unnecessary nesting of component structures
One of the most common mistakes developers make is nesting components for no reason. Doing this hurts performance and can also cause unappealing aesthetics in the app with oddities such as double borders or unexpected layout behaviour.
Example:
1A below, we have a panel that contains a single grid. In this case, the panel is unnecessary.
items: [{
xtype : 'panel',
title: ‘My Cool Grid’,
layout: ‘fit’,
items : [{
xtype : 'grid',
store : 'MyStore',
columns : [{...}]
}]
}]
As shown in example 1B, the extra panel can be eliminated. Remember that forms, trees, tab panels, and grids all extend from Panel, so you should especially watch for unnecessary nesting conditions whenever using these components.
1B below: The grid is already a panel so just use any panel properties directly on the grid.
layout: 'fit',
items: [{
xtype : 'grid',
title: 'My Cool Grid',
store : 'MyStore',
columns : [{...}]
}]
2. Failing to follow upper/lowercase naming conventions
There are certain upper/lowercase standards that Sencha follows when naming components, properties, xtypes, etc. To avoid confusion and to keep your code clean, you should follow the same standards.
Example 2A shows several incorrect scenarios. Example 2B shows the same scenarios with the correct upper/lowercase naming conventions.
2A:
Ext.define('MyApp.view.customerlist',{ // should be capitalized and then camelCase
extend : 'Ext.grid.Panel',
alias : ‘widget.Customerlist’, // should be lowercase
MyCustomConfig : ‘xyz’, // should be camelCase
initComponent : function(){
Ext.apply(this,{
store : ‘Customers’,
….
});
this.callParent(arguments);
}
});
2B GOOD: Areas in bold follow all of the correct upper/lowercase rules.
Ext.define('MyApp.view.CustomerList',{
extend : 'Ext.grid.Panel',
alias : 'widget.customerlist',
myCustomConfig : 'xyz',
initComponent : function(){
Ext.apply(this,{
store : ‘Customers’,
….
});
this.callParent(arguments);
}
});
Additionally, if you are firing any custom events, the name of the event should be all lowercase. Of course, everything will still work if you don’t follow these conventions, but why stray outside of the standards and write less clean code?
3.Making your code more complicated than necessary
There are many times we see code that is more complicated than necessary. This is usually a result of not being entirely familiar with each component’s available methods. One of the most common cases we see is code that loads each form field from a data record individually.
Example 3A shows an example of this.
BAD: Loading form fields from a record individually.
//suppose the following fields exist within a form
items : [{
fieldLabel : 'User',
itemId : 'username'
},{
fieldLabel : 'Email',
itemId : 'email'
},{
fieldLabel : 'Home Address',
itemId : 'address'
}];
// you could load the values from a record into each form field individually
myForm.down('#username').setValue(record.get('UserName'));
myForm.down('#email').setValue(record.get('Email'));
myForm.down('#address').setValue(record.get('Address'));
Instead of loading each value individually, use the loadRecord method to load all fields from the record into the proper form fields with one line of code. The key is to make sure the “name” property of the form field matches the field name of the record as shown in example 3B.
Use loadRecord to load all form fields with one line of code.
items : [{
fieldLabel : 'User',
name : 'UserName'
},{
fieldLabel : 'Email',
name : 'Email'
},{
fieldLabel : 'Home Address',
name : 'Address'
}];
myForm.loadRecord(record);
This is just one example of ways code can be more complicated than necessary. The point is to review all of a component’s methods and examples to make sure you are using simple and proper techniques.
4. Unreliable referencing of components
We sometimes see code that relies on component positioning in order to get a reference. This should be avoided as the code can easily be broken if any items are added, removed or nested within a different component.
Example 4A shows a couple common cases.
var mySaveButton = myToolbar.items.getAt(2);
var myWindow = myToolbar.ownerCt;
Example 4A. BAD: Avoid retrieving component references based on component positioning.
Instead, use ComponentQuery, or the component “up” or “down” methods, to retrieve references as shown in example 4B. With this technique the code will be less likely to break if the structure or ordering of components is subsequently changed.
var mySaveButton = myToolbar.down('#savebutton'); // searching against itemId
var myWindow = myToolbar.up(‘window');
5. Don’t Use of “id”
We don’t recommend the use of id’s on components because each id must be unique. It’s too easy to accidentally use the same id more than once, which will cause duplicate DOM id’s (name collisions). Instead, let the framework handle the generation of id’s for you. With Ext JS ComponentQuery, there is no reason to ever have to specify an id on an Ext JS component. Example 6A shows two code segments of an app where there are two different save buttons created, both of which were identified with an id of ‘savebutton’, causing a name collision. Although obvious in the code below, it can be hard to identify name collisions in a large application.
//here we define the first save button
xtype : 'toolbar',
items : [{
text : ‘Save Picture’,
id : 'savebutton'
}]
// somewhere else in the code we have another component with an id of ‘savebutton’
xtype : 'toolbar',
items : [{
text : ‘Save Order’,
id : 'savebutton'
}]
BAD: Assigning a duplicate ‘id’ to a component will cause a name collision.
Instead, if you want to manually identify each component you can simply replace the ‘id’ with ‘itemId’ as shown in example 5B. This resolves the name conflict, and we can can still get a reference to the component via itemId. There are many ways to retrieve a reference to a component via itemId. A few methods are shown in example 5C.
xtype : 'toolbar',
itemId : ‘picturetoolbar’,
items : [{
text : 'Save Picture',
itemId : 'savebutton'
}]
// somewhere else in the code we have another component with an itemId of ‘savebutton’
xtype : 'toolbar',
itemId: ‘ordertoolbar’,
items : [{
text : ‘Save Order’,
itemId: ‘savebutton’
}]