PDA

View Full Version : Referencing body of a child item when extending a container



elishnevsky
6 Aug 2009, 9:24 AM
Hi. When I extend a container, for some reason I cannot reference the body of its child items from either onRender() or afterRender() methods. Here, take a look at the code.


MyPanel = Ext.extend(Ext.Panel, {
width: 500,
height: 500,

initComponent: function() {
var config = {
layout: 'border',
items: [{
region: 'west',
title: 'West',
html: 'blah blah',
width: 200,
split: true,
margins: '5 0 5 5'
}, {
region: 'center',
title: 'Center',
html: 'Lorem ipsum dolor sit amet...',
margins: '5 5 5 0',
itemId: 'center-region',
ref: '../centerRegion'
}]
};
Ext.apply(this, config);
MyPanel.superclass.initComponent.call(this);
},

afterRender: function() {
MyPanel.superclass.afterRender.apply(this, arguments);

console.log(this.body);
console.log(this.getComponent('center-region'));
console.log(this.getComponent('center-region').body);
console.log(this.centerRegion);
}
});

console.log(this.getComponent('center-region')); outputs the object and you can see that it contains body member.

However console.log(this.getComponent('center-region').body); prints undefined.

Also ref config option on the center region doesn't seem to work.

What am I doing wrong?

Animal
6 Aug 2009, 9:36 AM
Try setting Ext.Container.prototype.bufferResize = false

That feature was not well thought through!

elishnevsky
6 Aug 2009, 9:43 AM
No, Nige, it doesn't make any difference.

Animal
6 Aug 2009, 9:50 AM
It works here. I see an Ext.Element being logged.

I'll just rebuild with the latest rev from SVN and try again... maybe you have downloaded a revision with a bug...

elishnevsky
6 Aug 2009, 9:53 AM
Here's full code of the page.
Referencing this.getComponent('center-region').body inside afterRender() method returns undefined.


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title id="page-title">demo</title>

<link rel="stylesheet" type="text/css" href="../ext-3.0.0/resources/css/ext-all.css"/>
<script type="text/javascript" src="../ext-3.0.0/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext-3.0.0/ext-all-debug.js"></script>

<script type="text/javascript">
Ext.BLANK_IMAGE_URL = '../ext-3.0.0/resources/images/default/s.gif';

MyPanel = Ext.extend(Ext.Panel, {
width: 500,
height: 500,

initComponent: function() {
var config = {
layout: 'border',
items: [{
region: 'west',
title: 'West',
html: 'blah blah',
width: 200,
split: true,
margins: '5 0 5 5'
}, {
region: 'center',
title: 'Center',
html: 'Lorem ipsum dolor sit amet...',
margins: '5 5 5 0',
itemId: 'center-region',
ref: '../centerRegion'
}]
};
Ext.apply(this, config);

MyPanel.superclass.initComponent.call(this);
},

afterRender: function() {
MyPanel.superclass.afterRender.apply(this, arguments);

console.log(this.body);
console.log(this.getComponent('center-region'));
console.log(this.getComponent('center-region').body);
console.log(this.centerRegion);
}
});

Ext.onReady(function() {
var panel = new MyPanel({
renderTo: document.body
});

console.log(panel.getComponent('center-region').body);
});
</script>
</head>
<body>
</body>
</html>

Tried to run it against the latest code from SVN, same result.

Animal
6 Aug 2009, 10:10 AM
I think it's an implementation error in Ext.Container.

It implements render which is incorrect.

Subclasses should insert their extra functionality at certain points of the lifecycle in template methods such as onRender and afterRender.

The problem was that afterRender gets called by Component.render which is obviously wrong. Rendering has NOT finished. The rest of the Container's extra logic happens in Container.render after the Component.render has all done. This is a major and glaring error. (I've a feeling I've pointed it out before)



Ext.override(Ext.Container, {
render: Ext.Component.prototype.render,

onRender : function(){
Ext.Container.superclass.onRender.apply(this, arguments);
if(this.layout){
if(Ext.isObject(this.layout) && !this.layout.layout){
this.layoutConfig = this.layout;
this.layout = this.layoutConfig.type;
}
if(Ext.isString(this.layout)){
this.layout = new Ext.Container.LAYOUTS[this.layout.toLowerCase()](this.layoutConfig);
}
this.setLayout(this.layout);

if(this.activeItem !== undefined){
var item = this.activeItem;
delete this.activeItem;
this.layout.setActiveItem(item);
}
}
},

afterRender : function(){
Ext.Container.superclass.afterRender.apply(this, arguments);
if(!this.ownerCt){
// force a layout if no ownerCt is set
this.doLayout(false, true);
}
if(this.monitorResize === true){
Ext.EventManager.onWindowResize(this.doLayout, this, [false]);
}
}
});


This o

Animal
6 Aug 2009, 10:16 AM
This will have had a few other bad effects.

Component.render also hides the Component if it had been configured with hidden: true

This would have been too soon - it's called after the afterRender method which is where any layout is now done.

Without this fix, layout would have been processed in the newly hidden Component.

elishnevsky
6 Aug 2009, 10:53 AM
Thanks for the override. That's exactly what I suspected. And yes, you are right, it's a major thing. Do you think I should post it in Bugs?

Animal
6 Aug 2009, 12:08 PM
Yes, definitely.