Reputation: 736
I was wondering how I should start making a custom composite component. One that has a border layout, but for which its items show in the center region of the border layout. The following image shows what I'm trying to achieve:
In pseudo-code this would be:
Ext.define('App.custom.ContentView', {
extend: 'Ext.container.Container',
xtype: 'contentview',
layout: 'border',
northCmp: ..., // Custom north region component.
westCmp: ..., // Custom west region component.
centerCmp: ..., // Placeholder for the items it will have.
items: [] // Filled in by each implementation, shown in the center region.
});
Ext.create('App.custom.ContentView', {
layout: 'vbox', // Applies to center region of 'contentview'.
items: [
// Items that go into the center region of the 'contentview'.
]
});
I have looked through the ExtJS source code, and viewed a couple of examples at the Sencha Market; but I have not found an obvious example that does not include a lot of duplicate code.
Any help, or nudge in the right direction, would be greatly appreciated! :)
Upvotes: 1
Views: 808
Reputation: 25031
You should not do that. Please, don't let me be misunderstood, your intentions are good but the implementation you describe will grip in some point in the future. I know because I did something similar when I debuted with Ext. The idea of tuning the component declaration to your tastes/need/whatever may seem like a pleasant simplification... Unfortunately, in practice what you want to do is to give another meaning to an existing construct (items
in your case). Here's what it will really bring you:
All code external to your application (that includes Ext, and Ext future releases!) will expect components/container to behave the classic way. That is, that the items of a container are really the items it contains, not the items of one of its children. Unexpected behaviour is to be expected.
You'll inevitably want to customize this component in some ways. You've already started, with the layout of the center region. If you rewrite the way the component work, you'll have to write some kind of config proxy to any feature you want to use. Big burden instead of a little saving. Doesn't worth it.
And finally, in some time you'll have forgotten all about what you've done with this component. And you'll have to debug your code just to understand what it is supposed to do (that is, before debugging the real issues).
Sorry for lecturing... All that being said, that doesn't mean there's not a way to come close to what you want without falling prey to reframing the framework.
Here's how I would do it (fiddle):
Ext.define('My.custom.BorderContainer', {
extend: 'Ext.container.Container'
// xtype is used in Ext3 and Touch... Ext4 uses aliases
,alias: 'widget.contentview'
,layout: 'border'
,items: [{
region: 'north'
,xtype: 'container'
,html: "<h1>Some header</h1>"
,style: 'background-color: lightblue;'
},{
region: 'west'
,xtype: 'container'
,split: true
,html: "<h1>Some menu</h1>"
,style: 'background-color: purple;'
},{
region: 'center'
,xtype: 'container'
}]
/**
* Configuration of the center panel.
*
* @cfg {Object/Ext.Component}
*/
,center: null
,initComponent: function() {
var center = this.center;
if (center) {
if (center instanceof Ext.Component) {
center.region = 'center';
} else {
// never modify a passed config object, that could
// break the expectations of the using code
center = Ext.clone(center);
// apply default config, including the region
center = Ext.applyIf(center, this.items[2]);
}
this.items[2] = center;
}
// else use default config, already in place
this.callParent(arguments);
}
});
Notice how I added a new center
config option instead of trying to recycle existing ones (items
, layout
, etc.). That allows me to put anything I want, customized to the bone, and with usual syntax, in that. Future me and coworkers will probably send me chocolates for that! For example:
Ext.widget('contentview', {
renderTo: Ext.getBody()
,height: 300
,center: {
layout: {
type: 'vbox'
,align: 'center'
}
,defaults: {
xtype: 'component'
,margin: 10
,padding: 10
}
,items: [{
html: 'Red'
,style: 'background-color: green;'
},{
html: 'Green'
,style: 'background-color: blue;'
},{
html: 'Blue'
,style: 'background-color: red;'
}]
}
});
Ext.widget('contentview', {
renderTo: Ext.getBody()
,height: 300
,center: {
xtype: 'tabpanel'
,tabPosition: 'bottom'
,items: [{
title: 'First Tab'
,html: "I'm empty!"
},{
title: 'Second Tab'
}]
}
});
Ext.widget('contentview', {
renderTo: Ext.getBody()
,height: 300
// passing a component instance instead of a config object
,center: Ext.widget('button', {
text: "Foo"
})
});
Upvotes: 1