Learning Ext JS(Fourth Edition)
上QQ阅读APP看书,第一时间看更新

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 the fullname class, the alias class, or the alternate 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 the xtype (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 is actioncolumn. 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 an Ext.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:

Writing your first class

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:

Writing your first class

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:

Simple inheritance

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.

Simple inheritance

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:

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:

Mixing many classes (the use of mixins)

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:

Mixing many classes (the use of mixins)

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:

Using the mixinConfig property

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 every config property. The auto-generated setter method calls the apply method internally before setting the value. You may override the apply method for a config property if you need to run custom logic before setting the value. If apply 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:

  1. We wrapped the properties of the Employee class in the config object.
  2. In the constructor method, we changed the old code and set only this.initConfig(config);.
  3. After creating the class, it will have the setters and getters methods for the properties: name, lastName, and age. 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 to age:
    • getAge
    • setAge
    • applyAge (this custom method will be launched automatically when setAge is invoked)
  4. After defining our class with the config object as a property, let's place the following code in the config_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:

Configurations

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:

Explanation

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 class

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 features
  • plugin: This is used for plugins
  • store: This is used for Ext.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:

Aliases

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.