
The class system
In version 4, the class system was completely redesigned and new features were added. It became a more powerful way to extend and create classes. And Ext JS 5 keeps the same structure and consistency as version 4.
In order to create classes, Ext JS uses the Ext.ClassManager
object internally to manage the associations between the names, aliases, or alternate names we define. And all classes (existing and new) use Ext.Base
as the base code.
It's not recommended to use these classes directly; instead we should use the following shorthands:
Ext.define
: This shorthand is used to create a new class, extend a class, or whenever we need to apply some override(s) in a class.Ext.create
: This shorthand creates a new instance of a class, using either thefullname
class, thealias
class, or thealternate name
class. Using any of these options, the class manager handles the correct mapping to create the class. We can also use this shorthand to create objects from an existing class.Ext.widget
: This shorthand is used to create a widget using thextype
(alias) property or a configuration object.Note
Alias is a short name for a class, which is usually easy to remember and handle in code, for example,
Ext.grid.column.Action
has an alias that isactioncolumn
. The full list can be found here: http://docs.sencha.com/extjs/5.1/5.1.1-apidocs/#!/api/Ext.enums.Widget.
Naming conventions
Ext JS uses consistent naming conventions throughout the framework. This allows you to have classes, namespaces, filenames, and so on, to keep an organized structure. As part of the coding conventions used by Sencha, there are some basic rules:
- Names may use alphanumeric characters, and you can use numbers, but as a convention, rule numbers may be used for technical terms. The use of underscores or hyphens may not be used as a convention rule, but it is not impossible to use them. For example:
MyApp.utils-common.string-renderers
(not good)MyApp.utils.Md5encyption
(good)MyApp.reportFormats.FM160
(good)
- Names should be grouped into
packages/namespaces
, spaced using object dot-notation as(namespace).(namespace).(class)
. You cannot repeat the top-level namespace followed by the class name. For example:MyApp.EmployeeApp
(good)MyApp.EmployeeApp.EmployeeClass
(not good; also this will be interpreted as a property rather than a class)
- The name for the top-level classes should be camel-cased. The groups and namespaces grouping of the top-level class should be in lowercase (again as a convention but not forbidden). For example:
MyApp.
grids.EmployeesGrid
MyApp.
data.clients.SalesReport
- As a rule and also to avoid possible errors, classes that are not part of the framework should never use
Ext
as the top-level namespace, unless you are creating anExt.ux
component. However, as a rule if you are using plugins or third-party components, be sure that the name(s) you are using do not collide or interfere with these plugins/components.
Writing your first class
So now let's create our first class using the first shorthand in the preceding list. In a new file called classes_01.js
, we need to write the following code:
Ext.define('Myapp.sample.Employee',{ name: 'Unknown', constructor: function (name){ this.name= name; console.log('class was created – name:' + this.name); }, work: function(task){ alert(this.name + ' is working on: ' + task); } }); var patricia = Ext.create('Myapp.sample.Employee', 'Patricia Diaz'); patricia.work('Attending phone calls');
In this code, we defined the name of the class as a string 'Myapp.sample.Employee'
as the first parameter of the Ext.define
function. Then we set the name
property and two methods: constructor
and work
.
When a new class is created, Ext
will use the constructor
method as a callback and it will be executed each time a new instance is created, giving us the chance to apply the initial configurations to the class. If constructor is not defined, Ext
will use an empty function and also the initial properties of the class will be the default values.
We now have the class already defined in the code, and a new instance of the class is created in the following code:
var patricia = Ext.create('Myapp.sample.Employee','Patricia Diaz');
We are telling Ext JS to create a new instance of the Myapp.sample.Employee
class and passing a one-string parameter, Patricia Diaz
, right after the execution of the code where the constructor method will be executed:
constructor: function(name){ this.name = name; console.log('class was created – name:' + this.name); },
Finally, we invoke the work
method, which will make an alert appear in the browser:
So far we have been handling one value in the class, and the usual way for most developers to do this is that we handle multiple values when creating classes, so let's change the code as shown in the following sample:
Ext.define('Myapp.sample.Employee',{ name: 'Unknown', lastName: 'Unknown', age: 0, constructor: function (config){ Ext.apply( this, config || {} ); console.log('class created – fullname:' + this.name + ' ' + this.lastName); }, checkAge:function(){ console.log( 'Age of ' + this.name + ' ' + this.lastName + ' is:' + this.age ); }, work: function( task ){ console.log( this.name + ' is working on: ' + task); } }); var patricia = Ext.create('Myapp.sample.Employee',{ name:'Patricia', lastName:'Diaz', age:21 }); patricia.checkAge(); patricia.work('Attending phone calls');
Let's review the changes. The parameter in the constructor
method was changed to config
, so now we will pass an object as a parameter to the constructor
method. Ext.apply(this, config || {});
will allow us to copy all the properties of the config
parameter to the class properties.
In order to run the example, we need to create an HTML page containing the following code snippet, and import the Ext JS library and the client class file (classes_01.js
), and after that we can execute the preceding code.
<!doctype html> <html> <head> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta charset="utf-8"> <title>My first ExtJS class</title> <script src="../ext-5.1.1/build/ext-all.js"></script> <script type ="text/javascript" src="classes_01.js"></script> </head> <body> </body> </html>
Open the HTML file in your favorite browser and the JavaScript console by pressing Ctrl + Shift + I (shortcut for Windows users) or Cmd + Option + I (shortcut for Mac users) to open the developer tools in Google Chrome.
If you're using Firefox, the shortcut to show the JavaScript console is Ctrl + Shift + K (for Windows users) or Cmd + Option + K (for Mac users). We should see two log messages in the JavaScript console as shown in the following screenshot:
The first message is printed in the console by the constructor
method that is executed when the Employee
class is created. The second message is printed when we have called the checkAge
method and accessed the age
property. Finally after we have called the work
method, the third message will appear.
Once we have the instance of the Employee
class, we can modify its properties by assigning the new value. If we refresh our browser, we will see a new message in the console and it will have the new value. We can create as many instances as we want from our class and every one of them will have the same properties and methods. However, we can change their values inpidually or even pass an object to the constructor with the properties that we want to change.
Simple inheritance
When we create a class using the Ext.define
method, we're extending from the Ext.Base
class. This class contains abstract methods that will be inherited by all the subclasses so we can use them at our convenience.
In our previous example, the Employee
class extends from the Base
class. We didn't have to do anything special to accomplish that. By default, if we don't configure a class to extend from any other class, it extends from the Base
class, and we should keep this in mind.
Most of the classes in the Ext
library extend from the Ext.Base
class, however there are a few core classes that don't. The following screenshot shows the inheritance tree for the Button
and Model
components:
As we can see in the previous image, the root of the tree is the Ext.Base
class, which means that the Button
and Model
components share the same methods defined in the Ext.Base
class.
In order to extend from any other class, we need to define the extend
property to our new class as follows; this will allow us to inherit all the methods and properties from the parent.
Ext.define('Myapp.sample.Supervisor',{
extend: 'Myapp.sample.Employee',
constructor: function ( config ){
Ext.apply(this, config || {});
console.log('class B created – fullname:' + this.name +
' ' + this.lastName);
},
supervise: function( employee ){
var employeefullname = employee.name + ' ' +
employee.lastname;
console.log( this.name + ' is supervising the work of '
+ employeefullname );
}
});
Here we have created a class that extends from the Myapp.sample.Employee
class just by adding the extend
property and assigning the name of the superclass in extend:'Myapp.sample.Employee'
. Also, we added a new method called supervise
, which will be available only to the Supervisor
class.
Let's make a duplicate of the files in the first example, and rename the HTML file to classes_02.html
and the JavaScript file to classes_02.js
. Now, change the script
tags that point the src
property to the new JavaScript file instead. At the end of the code in the classes_02.js
file, add the following code:
var robert = Ext.create('Myapp.sample.Supervisor',{ name: 'Robert', lastName: 'Smith', age: 34 }); robert.checkAge(); robert.work( 'Administration of the office' ); robert.supervise( patricia );
We used the Ext.create
method to create an instance of the Supervisor
class. In this example, we're passing new parameters. After the Supervisor
class is created, we run the same methods from Employee
class, and we also run the new method supervise
.
Let's open the HTML file in our browser and look at the JavaScript console. We should see the new logs from the Supervisor
class.
As we can see in this inheritance example, this property is also useful when we want to extend classes/widgets such as Ext.panel.Panel
and create our own panel while giving special and extra functionality that the panel does not provide.
Preprocessors and postprocessors
Every class in Ext JS is an instance of the Ext.Class
class. When we use the Ext.define
method to define a class, we are in fact creating an instance of the Ext.Class
class.
According to the documentation, the Ext.Class
class is a factory. This doesn't mean that our classes extend from the Ext.Class
class. As mentioned before, all classes extend from the Ext.Base
class. What this really means is that when we use the Ext.create
method, Ext runs processes behind the scenes. Each process is a task with a specific purpose in the whole process of creating the class.
A process may be asynchronous or not, for example, we have a preprocessor that loads all the dependencies for our new class if they are not already loaded. When the preprocessor finishes its tasks, the next process is executed until the list is empty and then our new class is created.
A preprocessor is a process that runs before the instance of an Ext.Class
class is created, or in other words, before our new class is created. Each of the processes defined will change the behavior of our class, if necessary.
A postprocessor is a process that runs after our new class is created. There is a process to make our class a singleton, to define alternative names for our class, and for a few other processes.
There are a few processes defined by the Ext
library, but we can define our own and add them to the process queue if we want.
The question now is what processes are we talking about? And what do they do? If we want to see the list of registered processes, we can execute the following lines of code:
var pre = Ext.Class.getDefaultPreprocessors(), post = Ext.ClassManager.defaultPostprocessors; console.log(pre); console.log(post);
By running the previous code in a browser, we should see the following messages in the JavaScript console:
["className", "loader", "extend", "privates", "statics", "inheritableStatics", "platformConfig", "config", "cachedConfig", "mixins", "alias"] ["alias", "singleton", "alternateClassName", "debugHooks", "deprecated", "uses"]
The following screenshot represents the flow of the class creation with the preprocessors and postprocessors:
This is what happens when we create a class. All the preprocessors run before the class is ready, modifying the result. The postprocessors on the other hand run when the class is ready to be used.
For example, the loader
process looks for the dependencies and if they are not present, it tries to load them synchronously. After all the dependencies are ready, it passes the control to the Ext.Class
class in order to continue with the next process. The following process in the queue is extend
, which is responsible for copying all the prototype methods and properties from the superclass to the subclass.
The following table shows a brief description of all the preprocessors that may be executed to create a new class:
Once the class is created, the following postprocessors are executed:
Sometimes processes won't run, so if this is the case we need to check out how we have configured and defined our classes. Sometimes, letters in lowercase and uppercase can make a big difference, so keep in mind that class names and property names have to be in the correct uppercase and lowercase syntax; otherwise, these processes or properties will be ignored.
Now that you have a basic understanding of how the class system works, we can advance on to how we can define our classes using the process logic and take advantage of them.
Mixing many classes (the use of mixins)
So far, you have learned about simple inheritance, but we can also mimic multiple inheritances using the mixins
processor. The concept is really simple: we can mix many classes into one. As a result, the new class will have access to all the properties and methods from the mixed classes.
Continuing with the previous classes, Employee
and Supervisor
, let's organize those classes a bit more. Occupations in the company can vary depending on the needs of the organizations; a secretary has different tasks to perform from a manager or an accountant. So we are going to separate the required tasks each occupation has to perform, and this way we will have some different classes with the tasks that people in the company can perform according to the occupation each one has.
The following diagram shows an example:
Let's make a duplicate of the classes_02.js
file and rename it classes_04.js
; also make a duplicate of the classes_02.html
HTML file and change the JavaScript file reference to classes_04.js
. And now we proceed to make some new changes in the classes_04.js
file. After the code where we defined the employee class, let's write the following code:
// Mixins Ext.define('Myapp.sample.tasks.attendPhone',{ answerPhone:function(){ console.log( this.name + ' is answering the phone'); } }); Ext.define('Myapp.sample.tasks.attendClient',{ attendClient:function(clientName){ console.log( this.name + ' is attending client: ' + clientName); } }); Ext.define('Myapp.sample.tasks.attendMeeting',{ attendMeeting:function(person){ console.log( this.name + ' is attending a meeting with ' + person); } }); Ext.define('Myapp.sample.tasks.superviseEmployees',{ superviseEmployee:function(supervisor, employee){ console.log( supervisor.name + ' is supervising : ' + employee.name + ' ' + employee.lastName); } });
For the sake of simplicity, we're just sending a log message to the console on each method. But we can do anything else needed. Now let's define the occupation classes, which contain a few methods (tasks) according to what each occupation can do.
As an example, a manager will not answer the phone, as this is the task of a secretary, and a secretary will not supervise any employee, as that is a task for a manager.
Ext.define('Myapp.sample.Secretary',{ extend:'Myapp.sample.Employee', mixins:{ answerPhone: 'Myapp.sample.tasks.attendPhone' }, constructor: function (config){ Ext.apply(this, config || {}); console.log('Secretary class created – fullname:' + this.name + ' ' + this.lastName); } }); Ext.define('Myapp.sample.Accountant',{ extend:'Myapp.sample.Employee', mixins:{ attendClient: 'Myapp.sample.tasks.attendClient', attendMeeting: 'Myapp.sample.tasks.attendMeeting' }, constructor: function (config){ Ext.apply(this, config || {}); console.log('Accountant class created – fullname:' + this.name + ' ' + this.lastName); } }); Ext.define('Myapp.sample.Manager',{ extend:'Myapp.sample.Employee', mixins:{ attendClient: 'Myapp.sample.tasks.attendClient', attendMeeting: 'Myapp.sample.tasks.attendMeeting', supervisePersons:'Myapp.sample.tasks.superviseEmployees' }, constructor: function (config){ Ext.apply(this, config || {});//this.name= config.name; console.log('Manager class created – fullname:' + this.name + ' ' + this.lastName); }, supervise: function(employee){ console.log( this.name + ' starts supervision '); this.mixins.supervisePersons.superviseEmployee(this, employee); console.log( this.name + ' finished supervision '); } });
Here we created three classes (Secretary
, Accountant
, and Manager
). Each class extends the Employee
class and on each class, a new configuration has been added: mixins:{...}
. And lastly, let's insert the following code at the end:
// Usage of each class var patricia = Ext.create('Myapp.sample.Secretary', {name:'Patricia', lastName:'Diaz', age:21 } ); patricia.work('Attending phone calls'); patricia.answerPhone(); var peter = Ext.create('Myapp.sample.Accountant', {name:'Peter', lastName:'Jones', age:44 } ); peter.work('Checking financial books'); peter.attendClient('ACME Corp.'); peter.attendMeeting('Patricia'); var robert = Ext.create('Myapp.sample.Manager', {name:'Robert', lastName:'Smith', age:34 } ); robert.work('Administration of the office'); robert.attendClient('Iron Tubes of America'); robert.attendMeeting('Patricia & Peter'); robert.supervise(patricia); robert.supervise(peter);
Once the code is ready, refresh the browser and you should see something like the following screenshot in the JavaScript console:
An explanation of mixins
Each class is based on the Employee
class. We then defined the employees
tasks (as classes) such as Myapp.sample.tasks.attendMeeting
and this was incorporated (mixed) into the respective class using the mixin{...}
configuration.
At the end, we have each class with methods like the ones in the following table:
Note that the supervise
method defined in Manager
uses the next code:
this.mixins.supervisePersons.superviseEmployee(this, employee);
This code lets us call the correct function defined in Myapp.sample.tasks.superviseEmployees
. Now let's make validations and perform other operations before we run the superviseEmployee
function.
Using the mixinConfig property
Using the mixinConfig
property makes the mixin
class able to provide before
or after
hooks that are not involved in the class (that is, the class we are going to be working with).
An easy way to understand this is that before and after settings can be configured to make some actions linked to the method being called. So the mixinConfig
settings will be working as a monitor (observable) and when the attached function is called, then will execute the method set on each configuration.
Also, the derived class cannot adjust parameters to the hook methods when these methods are called. In the next example, we are going to create a mixinConfig
in order to execute methods before and after answering the cell phone (the Secretary
class).
The following code implements the mixinConfig
for the Secretary
class:
Ext.define('Myapp.sample.tasks.attendCellPhone',{ extend: 'Ext.Mixin', /* answerCellPhone is the attached function for before and after and will execute the method defined in the answerCellPhone property on each configuration object (before / after) */ mixinConfig:{ before:{ answerCellPhone:'cellPhoneRinging' }, after:{ answerCellPhone:'finishCall' } }, cellPhoneRinging: function(){ console.log( 'cell phone is ringing you may attend call'); }, finishCall: function(){ console.log( 'cell phone call is over'); } });
Now we need to modify the Secretary
class as show in the following code:
Ext.define('Myapp.sample.Secretary',{ extend:'Myapp.sample.Employee', mixins:{ answerPhone: 'Myapp.sample.tasks.attendPhone', util:'Myapp.sample.tasks.attendCellPhone' }, constructor: function (config){ Ext.apply(this, config || {});//this.name= config.name; console.log('Secretary class created – fullname:' + this.name + ' ' + this.lastName); }, answerCellPhone:function(){ console.log( this.name + ' is answering the cellphone'); } });
Refresh the browser and you should see something like the following screenshot in the JavaScript console:
The important thing about mixins is that we can create classes to do specific tasks and then mix those classes into one. This way, we can reuse the same classes over and over again.
In the Ext
library, classes such as Ext.util.Observable
, Ext.util.Floating
, Ext.state.Stateful
, and others are treated like mixins
, as each class knows how to do specific things. This is something great for big applications and we should think wisely how we're going to structure our big application before we start coding.
Configurations
Another great feature that started in Ext JS version 4 is the addition of configurations. Usually when we create a class, we set configurations so we can change the values and behavior of our class depending on the input parameters. Since Ext JS 4, this process is really easy by adding a preprocessor to handle the configurations for us.
Here we have an example on how the version prior to version 4 had to define configurations/properties on the classes:
Ext.define('Myapp.sample.Employee',{ name:'Unknown', lastName: 'Unknown', age: 0, constructor: function (config){ Ext.apply(this, config || {});//this.name= config.name; console.log('class A created – fullname:' + this.name + ' ' + this.lastName); }, work: function( task ){ console.log( this.name + ' is working on: ' + task); }, setName: function( newName ){ this.name = newName; }, getName: function(){ return this.name; } });
In versions prior to version 4, we had to code the setName
and getName
methods in order to change properties in the class, which was time-consuming for developers. Since version 4, the config
property on classes let us avoid all this extra work thanks to the Ext JS preprocessors before the class is created. The features of the configuration are as follows:
- Configurations are encapsulated from other class members.
- Getter and setter methods for every
config
property are created automatically in the class prototype if they are not already defined. - An
apply
method (for example,setName
, will change its property name) is also generated for everyconfig
property. The auto-generated setter method calls theapply
method internally before setting the value. You may override theapply
method for aconfig
property if you need to run custom logic before setting the value. Ifapply
does not return a value, the setter will not set the value.
If you intend/plan to create a new class or component and you are extending the Ext.Base
class for this, then it's required that you call/use the initConfig()
method. On classes that are already using the config
property, you don't have the need to call the initConfig()
method.
For the next exercise, let's create a new file called config_01.js
and a HTML called config_01.html
. Place the necessary reference to the Ext JS library we have made in the previous samples and let's work on the code for the config_01.js
file, which will be as follows:
Ext.define('Myapp.sample.Employee',{ config:{ name: 'Unknown', lastName: 'Unknown', age: 0, isOld: false }, constructor: function ( config ){ this.initConfig( config ); }, work: function( task ){ console.log( this.name + ' is working on: ' + task); }, applyAge: function(newAge) { this.setIsOld ( ( newAge >= 90 ) ); return newAge; } });
In the preceding code, we performed the following steps:
- We wrapped the properties of the
Employee
class in theconfig
object. - In the constructor method, we changed the old code and set only
this.initConfig(config);
. - After creating the class, it will have the setters and getters methods for the properties:
name
,lastName
, andage
. Note that by setting up the class this way, we will have four new methods for each property. As an example, the following are the new methods related toage
:getAge
setAge
applyAge
(this custom method will be launched automatically whensetAge
is invoked)
- After defining our class with the
config
object as a property, let's place the following code in theconfig_01.js
file after the class definition for a test:var patricia = Ext.create('Myapp.sample.Employee',{ name: 'Patricia', lastName: 'Diaz', age: 21, isOld:false }); console.log( "employee Name = " + patricia.getName() ); console.log( "employee Last name = " + patricia.getLastName() ); console.log( "employee Age = " + patricia.getAge() ); patricia.work( 'Attending phone calls' ); patricia.setName( 'Karla Patricia' ); patricia.setLastName( 'Diaz de Leon' ); patricia.setAge ( 25 ); console.log("employee New Name=" + patricia.getName() ); console.log("employee New Last name=" + patricia.getLastName() ); console.log( "employee New Age = " + patricia.getAge() ); patricia.work('Attending phone calls'); var is_old=''; is_old= ( patricia.getIsOld() == true)? 'yes' : 'no' ; console.log( "is patricia old? : " + is_old ) ; patricia.setAge( 92 ); is_old=''; is_old= ( patricia.getIsOld() == true)? 'yes' : 'no' ; console.log( "is patricia old? : " + is_old );
As you can see in the highlighted code, we are using the setters and getters methods created automatically by initConfig(config)
. When we changed the age of the employee using patricia.setAge(92)
, the applyAge
method was invoked that changed the isOld
property in the class. Let's take a look at the console:
Statics methods and properties
The statics
methods belong to the class and not to the instance; therefore we can use statics
methods without an instance. Static members in a class can be defined using the statics config
. Again we alter the previous code to the following code:
Ext.define('Myapp.sample.Employee',{ statics:{ instanceCount: 0, payrollId: 1000, nextId : function(){ return ( this.payrollId + this.instanceCount ); } }, config:{ name: 'Unknown', lastName: 'Unknown', age: 0, isOld: false, payrollNumber: 0 }, constructor: function ( config ){ this.initConfig( config ); this.setPayrollNumber( this.statics().nextId() ); this.self.instanceCount ++; }, work: function( task ){ console.log( this.getName() + ' is working on: ' + task); }, applyAge: function( newAge ) { this.setIsOld ( (newAge >= 90) ); return newAge; }, getTotalEmployees: function(){ return this.statics().instanceCount; } }); var patricia = Ext.create('Myapp.sample.Employee', { name: 'Patricia', lastName: 'Diaz', age: 21, isOld: false }); console.log( "patricia payrollId = " + patricia.getPayrollNumber()); console.log( "total employees = " + patricia.getTotalEmployees()); var peter = Ext.create('Myapp.sample.Employee', { name: 'Peter', lastName: 'Pan', age: 16, isOld: false }); console.log( "Peter payrollId = " + peter.getPayrollNumber() ); console.log( "total employees = " + patricia.getTotalEmployees()); console.log( "instance(s) of employee class = " + Myapp.sample.Employee.instanceCount );
Explanation
We created the statics
configuration in the Employee
class:
statics:{ instanceCount: 0, payrollId: 1000, nextId : function(){ return ( this.payrollId + this.instanceCount ); } },
These values will be static to all instance classes. In the class config
property, we added payrollNumber:0,
; this number will be assigned automatically in the constructor
method:
this.setPayrollNumber( this.statics().nextId() ); this.self.instanceCount ++;
The instanceCount
will be incremented thanks to the this.self.instanceCount++
code. When you use the this.self
code inside the class, keep in mind that we are referring globally to the Myapp.sample.Employee
class itself.
In this case, we created two instances of the classes Patricia
and Peter
so let's refresh the browser and we should see something like the following screenshot in the JavaScript console:
The Singleton class
By definition, a singleton
class can't be instantiated more than once. It should be the same instance all the time. Ext allows us to create singleton
classes very easily with one postprocessor.
If we want a class to be singleton, we only need to set the singleton
property to true. This will fire the correct postprocessor. As practice, we need to change / add the following code at the beginning of the previous file and save it as singleton_01.js
:
Ext.define('Myapp.CompanyConstants',{ singleton: true, companyName: 'Extjs code developers Corp.', workingDays: 'Monday to Friday', website: 'www.extjscodedevelopers.com', welcomeEmployee: function (employee){ "Hello " + employee.getName() + ", you are now working for " + this.companyName; } });
As this class will be the only one and unique instance in our entire application code, there's no need to create a new instance or use Ext.create
. We simply call it by its name, for example:
alert( Myapp.CompanyConstants.companyName );
// will alert "Extjs code developers Corp."
After creating each Employee
class instance(s) inside the code, let's add the following lines:
var patricia = Ext.create('Myapp.sample.Employee', { name:'Patricia', lastName:'Diaz', age:21, isOld:false }); console.log(Myapp.CompanyConstants.welcomeEmployee(patricia)); var peter = Ext.create('Myapp.sample.Employee', { name:'Peter', lastName:'Pan', age:16, isOld:false }); console.log(Myapp.CompanyConstants.welcomeEmployee(peter));
Let's save the file and refresh the browser and we should see something like the following screenshot showing the JavaScript console:
The singleton classes are commonly used to hold constants, configurations, and common functions (commonly referred to as utility classes) for our application such as the base path of our application, the path where the images are located, and things like that.
Aliases
An alias is a short name for a class. The class manager maps /adds the alias name with the actual class object. By convention, an alias should be all in lowercase.
This feature is really useful when using the xtype
property to create widgets. Let's create a JavaScript file and name it alias_01.js
and place the following code in it:
Ext.define('Myapp.sample.EmployeePanel',{ extend: 'Ext.panel.Panel', alias: 'widget.employeePanel', alternateClassName: 'mycustomemployeepanel', title: 'Employee Panel', html: 'Employee content here..!' });
In the previous code, we're setting the alias
property with a short name. We're also using the widget
prefix to indicate we're creating a component. A component is a class such as a window, grid, or panel.
Also in the code we defined the alternateClassName
property, which lets us define other alternative names for our class. This property can be a string or an array object with multiple names, for example, ['employeepanel','customEmployeePanel', 'employeeboard']
.
In Ext JS, we have a list of namespaces to use for aliases:
feature
: This is used for Grid featuresplugin
: This is used for pluginsstore
: This is used forExt.data.Store
widget
: This is used for components
Now let's create our class using the alias
name. We have a few options to do this:
Ext.onReady (function(){ Ext.create('widget.employeePanel',{ title: 'Employee Panel: Patricia Diaz...', height:250, width:450, renderTo: Ext.getBody() }); });
As an alternative, we can also use the following code:
Ext.onReady (function(){ Ext.widget('employeePanel',{ //using the xtype which is employeePanel title: 'Employee Panel: Patricia Diaz...', height:250, width:450, renderTo: Ext.getBody() }); });
Also, create the HTML file named alias_01.html
. Make the changes to the HTML file so it will look like the following code:
<!doctype html> <html> <head> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta charset="utf-8"> <title>Extjs - Alias</title> <link rel="stylesheet" type="text/css" href="../ext-5.1.1/build/packages/ext-theme-neptune/build/resources/ext-theme-neptune-all.css"> <script src="../ext-5.1.1/build/ext-all.js"></script> <script src="../ext-5.1.1/build/packages/ext-theme-neptune/build/ext-theme-neptune.js"></script> <script type ="text/javascript" src="alias_01.js"></script> </head> <body style="padding:15px;"></body> </html>
Run the file in your browser and you may have a similar result as shown in the following screenshot:
Let's check out the explanation. We defined the new class Myapp.sample.EmployeePanel
extending the Ext JS class component Ext.panel.Panel
. As this class is in fact a widget, we declared the alias as widget.employeePanel
. As we said previously, Ext.ClassManager
handles the declaration of our extended class (the internal use of preprocessors and postprocessors) and defines/maps the alias for later use. So when we create a new instance of the new class Myapp.sample.EmployeePanel
, Ext JS will know how to handle and execute the code properly.
Also, we have other ways to reference the new class:
Ext.ClassManager.instantiateByAlias("widget.employeePanel",{ renderTo: Ext.getBody() }); // OR Ext.createByAlias("widget.employeePanel",{ renderTo: Ext.getBody() });
In this case, Ext.createByAlias
is the shorthand of Ext.ClassManager.instantiateByAlias
; they work the same way and usually it's easier to use the second option. Also we can refer to the new class by using its xtype
property on a configuration object, such as the following code:
var win = Ext.create("Ext.window.Window",{
title: "Window", width:350, height:250,
items: [{ xtype: "employeePanel" }]
});
win.show();
Note
Remember when extending a class, try to extend the class that gives you the properties and methods you really need in order to create your new class. Sometimes, it's bad practice to extend a class/widget such as Ext.panel.Panel
, if we are not going to take full advantage of the functionality it can provide us. In this case, perhaps it's more convenient to extend the panel base class, which is the Ext.container.Container
class.