PDA

View Full Version : Dynamically add panels to panels



inf3rno
29 Dec 2010, 6:34 AM
Hi!

I try to build a structure from a tree data and I have troubles.


var append=function (parent,child)
{
parent.add(child);
parent.doLayout();
};

var ColumnContainer=Ext.extend(Ext.Panel,
{
frame: true,
style: "text-align: center; margin: 3px; margin-bottom: 10px;",
layout: "hbox"
});

var Column=Ext.extend(Ext.Panel,
{
frame: true,
style: "text-align: center; margin: 3px; padding-bottom: 10px;"
});

var Text=Ext.extend(Ext.Panel,
{
frame: true,
style: "padding: 2px"
});
With normal build:


new ColumnContainer(
{
width: 600,
renderTo: Ext.getBody(),
items:
[
new Column(
{
title: "col1",
flex: 1,
items:
[
new ColumnContainer(
{
items:
[
new Column(
{
title: "col2",
flex: 1,
items:
[
new Text(
{
html: "text"
})
]
})
]
})
]
})
]
});
24014


With dynamic build:


var cc1=new ColumnContainer(
{
width: 600,
renderTo: Ext.getBody()
});

var c1=new Column(
{
title: "col1",
flex: 1
});
append(cc1,c1);

var cc2=new ColumnContainer();
append(c1,cc2);

var c2=new Column(
{
title: "col2",
flex: 1
});
append(cc2,c2);

var x1=new Text(
{
html: "text"
});
append(c2,x1);
24015


As you see the dynamic build fails by the second "hbox" layout, and I don't know why. Can anybody help me?

Condor
29 Dec 2010, 6:54 AM
append(cc1,c1) === c1.add(cc1) ?

You have to call container.doLayout() after adding items to the container.

In your case you only have to call c1.doLayout() once after adding all items.

inf3rno
29 Dec 2010, 11:20 AM
As I posted:


var append=function (parent,child)
{
parent.add(child);
parent.doLayout();
};
so
append(cc1,c1) === { cc1.add(c1); cc1.doLayout(); }

skirtle
29 Dec 2010, 2:47 PM
In the problem case you're building it from the outside in. The containers are initially empty so have no height. When you add items to the HBox layout it then sets their height to 0 to fit the container. Subsequent calls to doLayout() won't help because the whole system is in a zero-height equilibrium.

What you want is the opposite: for the containers to grow to fit their contents. Using inline items works fine because they are created from the inside out. The containers are initially sized to fit their children and then the HBox layout tries to set the children to the same height as their container. It's all a bit circular but because everything was the right height to start with it all works.

I can think of 3 ways to get your code working. Note these are 3 independent ways to fix it, there's no need to do all three. Take your pick.


Do what Condor suggested. Remove the parent.doLayout() from your append method and instead put a cc1.doLayout() at the very end of your code. This is my preferred solution.
Add autoHeight: true to your definition of Column. At the end call cc2.doLayout() followed by cc1.doLayout() to kick the two HBox layouts into behaving. This seems like a lot of extra pain compared to fix #1 but it does leave append unmodified.
Append the components in the opposite order: append(c2, x1); append(cc2, c2); append(c1, cc2); append(cc1, c1);

All three techniques seemed to work for me on IE 7, FF 3.6 and Chrome 8.

In general you're going to find this whole layout problematic though because you're relying on containers resizing to fit their children rather than the other way round. If you can put a fixed height on the outermost panel it'll make doing the layout for the children much easier. It's then just a case of a few fit layouts and some stretch-aligned HBoxes and everything just falls into place.

inf3rno
29 Dec 2010, 4:27 PM
I'll write a loader to build this tree automatically from a json or other text format. I can build it from inside out, it's not a problem, but I'll modify the tree with drag-drop and other controllers, I'll append, insert, move, remove items on the fly... How can I do that?

skirtle
30 Dec 2010, 1:47 AM
Technique #2 above will work, but it is going to get increasingly painful as your app gets more complicated...

All the problems stem from trying to resize the outermost container based on the innermost content. Is that really what you want in your finished app? If, as I suspect, this is just a prototyping harness then save yourself some pain and specify a fixed height on cc1. You should probably specify a suitable layout for Column too.

Incidentally, have you considered using a column layout instead of implementing columns yourself?

inf3rno
30 Dec 2010, 4:42 AM
The autoHeight works, thanks a lot!

I tried out columnLayout, but with the " hbox flex" property it's much easier to display my data.