1. #1
    Sencha User
    Join Date
    Feb 2011
    Posts
    174
    Answers
    10
    Vote Rating
    1
    netemp is on a distinguished road

      0  

    Default Answered: ExtJs 4.1 - Inheritance issue - Siblings values getting overridden

    Answered: ExtJs 4.1 - Inheritance issue - Siblings values getting overridden


    As a test case I have extended the textfield and created a class - Ext.mine.TextParent with xtype as textParent.

    This class is further being extended by two other classes - Ext.mine.child.TextChildA (xtype - textChildA) and Ext.mine.child.TextChildB (xtype - textChild).

    I have added a new config property to parent class as testConfig with defalult value being {}.

    In the initComponent of Child A class, I have assigned a new key:value to this testConfig as - me.testConfig.childAKey='Child A Value';

    Now, there is a form which is using all the three textfields and in the afterrender of the textChildB type, I am printing the value of its testConfig.

    As the value of testConfig is not modified in Child B, thus, it is expected that this should print blank object (because value of testConfig is blank in the parent).

    But it actually prints the values from Child A.

    Child A and Child B are siblings, thus, how can the value from Child A come to Child B?

    Is this a bug or are we doing something wrong?

    Below is the test case:


    Code:
    <html>
        <head>
            <title>Inheritance Test</title>
            <link rel='stylesheet' href='resources/extjs/resources/css/ext-all.css' />
            <script type='text/javascript' src='resources/extjs/ext-all-dev.js'></script>
            
            <script type='text/javascript'>
                
                //Defining the Parent below
                Ext.define('Ext.mine.TextParent', {
                    extend: 'Ext.form.field.Text',
                    alias: 'widget.textParent',
                    testConfig:{}
                });
                
                //Defining the Child A below
                Ext.define('Ext.mine.child.TextChildA', {
                    extend: 'Ext.mine.TextParent',
                    alias: 'widget.textChildA',
                    initComponent:function(){
                        var me    =    this;
                        me.testConfig.childAKey        =        'Child A Value';//Adding the key value to Child A
                        me.callParent();
                    }
                });
                
                //Defining the Child B below
                Ext.define('Ext.mine.child.TextChildB', {
                    extend: 'Ext.mine.TextParent',
                    alias: 'widget.textChildB'
                });
            </script>
            
            <script type='text/javascript'>
            
                Ext.onReady(function(){
                    Ext.create('Ext.form.Panel', {
                        title: 'Basic Form',
                        renderTo: Ext.getBody(),
                        width: 350,
                        url: 'save-form.php',
                        items: [{
                            xtype: 'textParent',//Creating field for Parent
                            fieldLabel: 'Text Parent',
                            flex:1
                        },{
                            xtype: 'textChildA',//Creating field for Child A
                            fieldLabel: 'Text Child A',
                            flex:1
                        },{
                            xtype: 'textChildB',//Creating field for Child B
                            fieldLabel: 'Text Child B',
                            flex:1,
                            listeners:{
                                afterrender:function(){
                                    /*
                                        **Printing to console the value of testConfig for Child B
                                        **Instead of giving a blank object, it is giving the values of Child A - childKey:Child A Value
                                        **How the value from a sibling got associated with another one?
                                    */
                                    console.log(this.testConfig);
                                }
                            }
                        }]
                    });
                });
            </script>
            
        </head>
        <body>
        </body>
    </html>

    Could anyone guide at this?

    Thanks for any help in advance.

  2. One approach looks like this:

    Code:
    Ext.define('Parent', {
        ...
        initComponent: function() {
            this.testConfig = this.createTestConfig();
    
            this.callParent();
        },
    
        createTestConfig: function() {
            return {};
        }
    });
    
    Ext.define('Child', {
        extend: 'Parent',
    
        createTestConfig: function() {
            // In this really simple case calling the superclass is unnecessary
            var config = this.callParent();
    
            config.name = this.name;
    
            return config;
        }
    });
    Further reading:

    http://skirtlesden.com/articles/conf...-the-prototype

  3. #2
    Sencha Premium Member skirtle's Avatar
    Join Date
    Oct 2010
    Location
    UK
    Posts
    3,605
    Answers
    543
    Vote Rating
    326
    skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future

      0  

    Default


    It's just a shared reference, not a library bug.

    The testConfig object will be on the prototype of TextParent. All instances will be sharing the same object. You can induce problems with much simpler cases.

    Code:
    Ext.define('TextParent', {
        extend: 'Ext.form.field.Text',
    
        testConfig: {},
    
        initComponent: function() {
            this.callParent();
            this.testConfig.name = this.name;
        }
    });
    
    var john = new TextParent({name: 'John'});
    var gary = new TextParent({name: 'Gary'});
    
    console.log(gary.testConfig.name); // logs 'Gary'
    console.log(john.testConfig.name); // also logs 'Gary'

  4. #3
    Sencha User
    Join Date
    Feb 2011
    Posts
    174
    Answers
    10
    Vote Rating
    1
    netemp is on a distinguished road

      0  

    Default


    Quote Originally Posted by skirtle View Post
    It's just a shared reference, not a library bug.

    The testConfig object will be on the prototype of TextParent. All instances will be sharing the same object. You can induce problems with much simpler cases.
    Thanks for the reply Skirtle.

    If this is the case, then could you please guide that what is the best way to add a new property to a class so that such a conflict does not arise?

    Thanks for the time so far.

  5. #4
    Sencha Premium Member skirtle's Avatar
    Join Date
    Oct 2010
    Location
    UK
    Posts
    3,605
    Answers
    543
    Vote Rating
    326
    skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future

      1  

    Default


    One approach looks like this:

    Code:
    Ext.define('Parent', {
        ...
        initComponent: function() {
            this.testConfig = this.createTestConfig();
    
            this.callParent();
        },
    
        createTestConfig: function() {
            return {};
        }
    });
    
    Ext.define('Child', {
        extend: 'Parent',
    
        createTestConfig: function() {
            // In this really simple case calling the superclass is unnecessary
            var config = this.callParent();
    
            config.name = this.name;
    
            return config;
        }
    });
    Further reading:

    http://skirtlesden.com/articles/conf...-the-prototype

  6. #5
    Sencha User
    Join Date
    Feb 2011
    Posts
    174
    Answers
    10
    Vote Rating
    1
    netemp is on a distinguished road

      0  

    Default


    Thanks for the post Skirtle. You are truly a "Jewel in the rough".

    Also, article suggested for further reading is brilliant.

    But just a small doubt, is it correct to add things to prototype, esp. thinking in the context of OOP where two siblings are expected to be completely independent of each other?

  7. #6
    Sencha Premium Member skirtle's Avatar
    Join Date
    Oct 2010
    Location
    UK
    Posts
    3,605
    Answers
    543
    Vote Rating
    326
    skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future skirtle has a brilliant future

      1  

    Default


    It isn't as simple as right and wrong when it comes to putting reference types on the prototype. From a subclassing perspective it's safer to avoid putting them on the prototype but that comes at the price of making your code much more complicated.

    Listeners frequently suffer from the hiding problem. Ajax proxy's actionMethods property is an example where modifying the object can cause problems for other instances.

    I'm afraid there is no short cut on this, you just have to understand what's going on and design accordingly.

  8. #7
    Sencha User
    Join Date
    Feb 2011
    Posts
    174
    Answers
    10
    Vote Rating
    1
    netemp is on a distinguished road

      0  

    Default


    Sure. Thanks again for all the help.

Thread Participants: 1

Tags for this Thread