In ExtJS components how to forward config: {} items to sub components
Solution 1
First something in general
Never add an object outside a function within a class definition unless you exactly know what you are going to do. Cause if you do so all instances will share the same instance of that object. I think I do not need to mention where this leads to...
If you have a need to place a object there you should clone it within the constructor.
To your code
I dunno what this.initConfig(config);
does but the config
variable is not the one from your class, it is the one from the constructor argument. I recommend you also to use initComponent()
for initialization instead of the constructor()
unless you have a defined need for using the constructor, which in your case you don't seem to have.
Also a 'config' is not forwarded cause it don't get executed up->bottom but bottom->up where a config get's hand up and all other properties are (already) inherited.
I still do not exactly know what your goal is, therefore I cannot give you any advice how you should do this but I can say for sure that the way you do it will lead to problems.
Edit
I still not sure that I have fully understand your needs but the following should work (if you need the listeners too you might take a look at the Ext.util.Bindable
mixin)
Ext.define('MyApp.view.items.ItemSelectorPanel', {
extend: 'Ext.panel.Panel',
require: 'MyApp.view.items.SimpleItemGrid',
alias: 'widget.ItemSelectorPanel',
layout: 'form',
initComponent: function() {
// Initialize the store (might be a instance or a storeId)
var store;
if (this.itemStore) {
store = Ext.data.StoreManager.lookup(store);
}
this.itemStore = store || null;
// Add is not valid (at least not before the parent inits are executed)
this.items = [{
fieldLabel: 'Filter',
name: 'filter'
}, {
xtype: 'SimpleItemGrid',
collapsible: true,
store: this.getItemStore()
}];
this.callParent(arguments);
},
getItemStore: function() {
return this.itemStore;
}
});
Solution 2
No, you can't do it in the way you've described. The reason is pretty simple, let's take this as an example:
Ext.define('MyClass', {
someProp: this.foo(),
foo: function(){
return bar;
}
});
Here, we call the define() method and we pass it an object as the configuration. As such, the whole object (including the call to foo()) is evaluated before it's even passed to define, so the class/method doesn't even exist at that point.
Even if you could do that, here's also the complication that foo is an instance method on the class, but the way you're attempting to call it is as though it's a static method.
So, the answer is, you'll need to use some kind of method to do so, initComponent is typically preferred over the constructor.
Solution 3
You can define items in declaration of your class but you cannot call any method from your class at time of declaration. To solve it, define only items without store and than use initComponent method to set store for your view.
Solution 4
I didn't see an answer that addressed the original question. Here is what I've found to work ...
Creating an instance of myClass, passing in a config 'foo' with value 'bar'
var myClassInstance = Ext.create('MyApp.view.myClass', {
foo: 'bar'
});
myClass is defined as follows :
Ext.define('MyApp.view.myClass', {
extend: 'Ext.container.Container',
alias: 'widget.myclass',
config: {
foo: 'defaultVal'
},
constructor: function(configs) {
this.callParent(arguments); //create class, calls initComponent
var try1 = getFoo(); //try1 is 'defaultVal'
this.initConfig(configs); //initializes configs passed in constructor
var try2 = getFoo(); //try2 is 'bar'
},
initComponent: function() {
//myClass declaration here ...
this.callParent();
}
ErosC
Updated on June 12, 2022Comments
-
ErosC almost 2 years
I am trying to write a reusable item selection panel where the user has a grid with items he can choose from and a small text field that he can use to filter the content of the grid. Right now the (simplified) view code looks like this and works.
Ext.define('MyApp.view.items.ItemSelectorPanel', { extend: 'Ext.panel.Panel', require: 'MyApp.view.items.SimpleItemGrid', alias: 'widget.ItemSelectorPanel', layout: 'form', config: { itemStore: false }, constructor: function(config) { this.initConfig(config); this.superclass.constructor.call(this, config); this.add([ { fieldLabel: 'Filter', name: 'filter' }, { xtype: 'SimpleItemGrid', collapsible: true, store: this.getItemStore() } ]); return this; } });
As you can see the
ItemSelectorPanel
uses theconfig
property to expose an interface where the calling site can specify which item store to use.Calling site (in this case the panel is added to a TabPanel):
var panelToAdd = { xtype: 'panel', title: 'New Selection', closable: true, padding: 10, items: [{ title: 'Select node', xtype: 'ItemSelectorPanel', itemStore: itemStore }] };
Now, I love the declarative style of ExtJS 4 and how it helps to follow the MVC pattern. I would prefer to have the least amount of code possible in the views. Unfortunately this does not work:
Ext.define('MyApp.view.items.ItemSelectorPanel', { /* ... same as above ... */ constructor: function(config) { this.initConfig(config); this.superclass.constructor.call(this, config); return this; }, items: [ { fieldLabel: 'Filter', name: 'filter' }, { xtype: 'SimpleItemGrid', collapsible: true, store: this.getItemStore // <-- interesting part } ] });
Is there a way to expose the config of a nested/sub component via the
config
property of the parent property in a declarative manner? -
Reimius over 11 yearsWhat the original asker has posted is valid, there are examples on the extjs website showing the exact same method of initialization. There is a special case when you create an object called 'config' at the class level that involves a standard initConfig function. Is it appropriate for his situation here though..? no. He should really be doing what you describe.
-
sra over 11 years@Reimius Absolutely! But as far as I know that is only when you define a 'superclass'. At least that is the only situations where I have ever used this. Or am I wrong?
-
ErosC over 11 years@sra Have a look here link. They take the cfg constructor parameter (not the config variable, as you also pointed out) and put it into the initConfig() call. What I am trying to achieve is to present the 'store' property of the SimpleItemGrid to the caller such that it looks as if it was a property of the ItemSelectorPanel. I want the internal details of the ItemSelectorPanel to be hidden from the outside world.
-
ErosC over 11 yearsCan you show an example for that? I tried ` initComponent: function () { Ext.getCmp('abcd').reconfigure(this.getItemStore()); }, items: [ { fieldLabel: 'Filter', name: 'filter' }, { xtype: 'SimpleItemGrid', itemId: 'abcd', collapsible: true } ] ` Tells me that I am calling reconfigure() on undefined.
-
ErosC over 11 yearsThe whole config property handling seems to be somehow tied to the constructor. I tried moving it to initComponent but I got errors. Also the documentation puts it into the constructor.
-
sra over 11 years@ErosC They are both superclasses and you will not need to access these core properties to archive your goal. See my edit