📜 ⬆️ ⬇️

Ext JS - Learning how to write components. Inheritance and nested configs

Good afternoon, dear habravchane. Continuing the topic of creating custom components, we will talk today about the inheritance of object properties and the proper use of event handlers.

When a project grows from a simple “mold with a grid and a button” to a complex RIA application, you have to make separate parts of the interface into components. Beginner ExtJS developers are trying to just put the entire configuration of a panel into an extend instruction:
var MyPanel = Ext.extend(Ext.Panel, { items: [{ xtype: 'grid' ................................................... * This source code was highlighted with Source Code Highlighter .
  1. var MyPanel = Ext.extend(Ext.Panel, { items: [{ xtype: 'grid' ................................................... * This source code was highlighted with Source Code Highlighter .
  2. var MyPanel = Ext.extend(Ext.Panel, { items: [{ xtype: 'grid' ................................................... * This source code was highlighted with Source Code Highlighter .
  3. var MyPanel = Ext.extend(Ext.Panel, { items: [{ xtype: 'grid' ................................................... * This source code was highlighted with Source Code Highlighter .
  4. var MyPanel = Ext.extend(Ext.Panel, { items: [{ xtype: 'grid' ................................................... * This source code was highlighted with Source Code Highlighter .
var MyPanel = Ext.extend(Ext.Panel, { items: [{ xtype: 'grid' ................................................... * This source code was highlighted with Source Code Highlighter .


and they get the cutest error in the firebug console (or they don’t know why they don’t display anything if this tool isn’t installed).

After reading the documentation on the ExtJS forum, they apply the solution recommended there:
  1. var MyPanel = Ext.extend (Ext.Panel, {
  2. initComponent: function () {
  3. Ext.applyIf ( this , {
  4. items: [
  5. ..............................
  6. });
  7. MyPanel.superclass.initComponent.call ( this );
  8. }
  9. ....................................
* This source code was highlighted with Source Code Highlighter .

')
Now everything works and everyone is happy. But unfortunately, no one wonders, why is a solution possible only in this way? And in vain. After all, later, when their own components start to appear additional properties, which are objects or arrays (for example, the parameters of AJAX requests), "fun" bugs will certainly arise. Consider the following example:

  1. Ext.ux.BadForm = Ext.extend (Ext.Panel, {
  2. border: false ,
  3. frame: true
  4. messages: {
  5. hello: 'Hello, World!'
  6. },
  7. html: 'Bad Form' ,
  8. buttons: [{
  9. text: 'Say' ,
  10. handler: function () {Ext.Msg.alert ( 'Message' , this .ownerCt.ownerCt.messages.hello); }
  11. }, {
  12. text: 'Change Msg' ,
  13. handler: function () { this .ownerCt.ownerCt.messages.hello = 'New Hello Message' ; }
  14. }]
  15. });
* This source code was highlighted with Source Code Highlighter .


If you create two instances of such a panel, a very interesting error will emerge. By pressing the Say button, both forms will give the standard message “Hello, World!”. But if you change the message in any of them, it will change in the other. How can this be, if we have two different instances of a class?

Everything is very easy to explain. In JavaScript, there is actually no such clear distinction as a class and an object. All frameworks usually emulate the usual inheritance scheme in ordinary OOP, providing tools like Ext.extend () / Class.create () / new Class () (Ext JS / Prototype / MooTools). In fact, each object is constructed on the basis of the prototype. The prototype is the same for all.

Everything that we put inside the object literal in the Ext.extend () method will be related to
the prototype (“class”) of the object, but the contents of the methods will be executed at the object level (“class instance”). When an object is created, the contents of the prototype are transferred to the object. But at the same time only scalar properties (numbers, strings) are actually copied. Properties-objects and methods are passed by reference. Any object created sees all the properties of the prototype, if they are not pre-defined. But all types given in JavaScript are objects and are passed by reference, only the scalars are immutable (thanks to mbezoyan habraiser for correct interpretation of the properties of the prototype). Thus, at the level of all instances of the “class” BadPanel, messages will indicate the same memory area. And the change of the message from one copy will be reflected in all.

To prevent such errors, the properties-objects are initialized in the initComponent method, i.e. at the object level, and not at the prototype level, as is done in the GoodForm “class”:

  1. Ext.ux.GoodForm = Ext.extend (Ext.Panel, {
  2. border: false ,
  3. frame: true
  4. initComponent: function () {
  5. Ext.applyIf ( this , {
  6. messages: {
  7. hello: 'Hello, World!'
  8. },
  9. buttons: [{
  10. text: 'Say' ,
  11. handler: function () {Ext.Msg.alert ( 'Message' , this .messages.hello); },
  12. scope: this
  13. }, {
  14. text: 'Change Msg' ,
  15. handler: function () { this .messages.hello = 'New Hello Message' ; },
  16. scope: this
  17. }]
  18. });
  19. Ext.ux.GoodForm.superclass.initComponent.call ( this );
  20. },
  21. html: 'Good Form'
  22. });
* This source code was highlighted with Source Code Highlighter .


We also want to note that the possibility of inheritance is not violated. Ext.applyIf method is used. It will install only those properties that do not exist. Thus, if during the creation of the GoodForm object you sent your set of messages (config) via the config, it will not be overwritten.

Under the link http://habrdemos.ibpro.com.ua/shared-resources-demo.html you can view an example of the work of the "good" and "bad" forms.

PS As you noticed, the initialization of the buttons in the initComponent method made it possible to simplify the receipt of the message text. But we will talk about this in the next article in the event handler cycle.

Source: https://habr.com/ru/post/91323/


All Articles