PDA

View Full Version : ExtJs 4.1 - Inheritance issue - Siblings values getting overridden



netemp
5 Jul 2012, 11:13 PM
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:




<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.

skirtle
6 Jul 2012, 5:52 AM
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.


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'

netemp
6 Jul 2012, 10:24 PM
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.

skirtle
7 Jul 2012, 4:29 AM
One approach looks like this:


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/config-objects-on-the-prototype

netemp
9 Jul 2012, 6:19 AM
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?

skirtle
9 Jul 2012, 6:40 AM
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.

netemp
9 Jul 2012, 7:01 AM
Sure. Thanks again for all the help.