You can incorporate features of Ext JS into your own JavaScript classes. For example, the ObservableList
class created in this recipe will use the features of the framework's Ext.util.Observable
class to fire notifications when items are added, removed, or when the list is cleared. The list's interface will be as follows:
add(object):
A function that inserts an item in the list and returns the position into which the item was insertedinsert(index, object):
A function that inserts an item to theList
at the specified indexitem(index):
A function that returns the element at the specified indexremove(object):
A function to remove the first occurrence of a specific objectremoveAt(index):
A function in charge of removing the item at the specified indexeach(fn, scope):
A method that executes the specified function once for every item in the list
Let's proceed to build and test the ObservableList
class as shown in the following steps:
1. Define the
ObservableList
class:Ext.namespace("Samples"); Samples.ObservableList = function() { this.items = []; this.length = 0; // The events our custom class will expose. // The parent Class, Observable, will handle event publishing //for us. this.addEvents("add", "remove", "clear"); Samples.ObservableList.superclass.constructor.call(this); };
2. Inherit the
Observable
class's functionality by establishing our class as an extension ofObservable:
3. Now, implement our class's interface:
Ext.extend(Samples.ObservableList, Ext.util.Observable, { allowFunctions: false, //Adds an item to the list and //returns the position into which the new element was inserted. add: function(o) { this.items.push(o); this.length++; // Fire the add event, returning the position // into which the new element was inserted. pos = this.length - 1; this.fireEvent("add", pos); return pos; }, // Inserts an item to the List at the specified index. insert: function(index, o) { //If the index is outside the list, insert the element at // the end of the list. if (index >= this.length) { return this.add(o); } this.length++; this.items.splice(index, 0, o); this.fireEvent("add", index); }, // Removes all items from the list. clear: function() { this.length = 0; this.items = []; this.fireEvent("clear"); }, // Determines the index of a specific item in the list. indexOf: function(o) { return this.items.indexOf(o); }, // Determines whether the List contains a specific value. contains: function(o) { return this.indexOf(o) != -1; }, // Our enumerator function. Executes the specified function //once for every element in the list. each: function(fn, scope) { var items = [].concat(this.items); for (var i = 0, len = items.length; i < len; i++) { if (fn.call(scope || items[i], items[i], i, len) === false) { break; } } }, custom JavaScript classescustom JavaScript classesbuilding// Removes the item at the specified index. removeAt: function(index) { if (index < this.length && index >= 0) { this.length--; var o = this.items[index]; this.items.splice(index, 1); this.fireEvent("remove", o); } }, // Removes the first occurrence of a specific object. remove: function(o) { this.removeAt(this.indexOf(o)); }, // Return the element at the specified index. item: function(index) { var item = this.items[index]; return item; } }); Samples.ObservableList.prototype.get = Samples.ObservableList.prototype.item;
4. It's time to test our class. Let's do it as follows:
Ext.onReady(function() { list = new Samples.ObservableList(); for (var i = 0; i < 15; i++) { pos = list.add("test " + i); } // Add handlers for the list's events. list.on("remove", function(o) { alert("Removed: " + o); }); list.on("add", function(index) { alert("Added at position: " + index); }); list.on("clear", function() { alert("List length is: " + list.length); }); document.write("List length is " + list.length + "<br/>"); // Insert an additional element and //check that the add event fires. var index = 2; list.insert(index, "A new item"); document.write("Just inserted: " + list.item(index) + "<br/>"); document.write("List length is: " + list.length + "<br/>"); // Remove an item an verify that the remove event fires. index = 5; document.write("Removing item at position" + index + "<br/>"); list.removeAt(index); document.write("List length after removal: " + list.length + "<br/>"); document.write("Clearing list...<br/>"); // Remove all items and check that the clear event fires. list.clear(); document.write("List length after clear: " + list.length + "<br/>"); });
A powerful mechanism for extending classes is provided by Ext JS with Ext.extend(subclass, superclass, [overrides])
. This function allows you to extend one class with another class and, optionally, to override the superclass's members.
Our example first defines the custom ObservableList
class and passes its events to the parent, Ext.Observable
. It then uses Ext.extend(subclass, superclass, [overrides])
not only to establish that the custom class implements Ext.Observable
, but also to define the bulk of its own interface—the add(object), insert(index, object), clear(), indexOf(object), each(fn, scope), removeAt(index), remove(object)
, and item(index)
functions.
Multiple versions of this approach are used by Ext JS to define its own class hierarchy. I encourage you to examine the source code of the library in order to get familiar with them.
The Adding features to the Ext JS classes recipe, covered earlier in this chapter, explains how to add new functions to the Ext JS classes
The A custom column layout recipe from Chapter 2 is an example of how to extend the native Ext JS layouts
The A three-panel application layout with one line of code recipe from Chapter 2 shows how to build a reusable Ext JS component that encapsulates a three-panel layout