PDA

View Full Version : Ext.ux.layout.AutoTableFormLayout: Multiple fields, Buttons+Text right besides fields



wuschba
17 Jul 2008, 2:06 AM
Hello.

JsExt has a very easy way to create forms on a FormPanel, but when it comes to more complex forms you have to deal with tables, colspans and so on. A second thing is that people often ask for things like "How do I get a text/button right beside a field?", which can not by easily done in a FormLayout.

Because I needed that features as well I wrote some code which does this on a - I hope - very easy base. As you can see from the code it's based on other code I got here on the forum - so thanks to mbajema, Animal and jgarcia@ tdg-i.com (and all others for their help to get me started with JsEXT). The code has not yet been finished (when will code ever be finished ;)) and every bug-report, more efficient code and additional functionality is very welcome.

I will keep the actual version of the code in this post.

Features:
- Easy to create a form with multiple fields in a row
- Class for a button on a form
- Class for text/html on a form

ToDos:
- A anchor-layout should be added to make the fields relatively scalable
- The handling of the labelSeparator, the padding and the labelStyle is kind of hacked and should be improved



// Version: 11. August 2008

// AutoTableFormLayout
// Based on http://extjs.com/forum/showthread.php?t=39342 by mbajema and Animal

Ext.namespace('Ext.ux.layout');

// Make the fieldTpl available to ALL layouts
Ext.override(Ext.layout.ContainerLayout, {
fieldTpl: (function() {
var t = new Ext.Template(
'<div class="x-form-item {5}" tabIndex="-1">',
'<label for="{0}" style="{2}" class="x-form-item-label">{1}{4}</label>',
'<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
'</div><div class="{6}"></div>',
'</div>'
);
t.disableFormats = true;
return t.compile();
})()
});

Ext.ux.layout.AutoTableFormLayout = Ext.extend(Ext.layout.TableLayout,
{
labelSeparator: ':',

setContainer: function(ct)
{
// Creating all subitems, figure out how many columns we need
this.columns = 1;
var aCols = new Array();
for(var i = 0, len = ct.items.length; i < len; i++)
{ var mainItem = ct.items.itemAt(i);
if (mainItem.fieldLabel == "") mainItem.labelSeparator = "";
mainItem.labelWidth = mainItem.labelWidth || ct.labelWidth || 100;
mainItem.colspan = mainItem.colspan || 1;

var cols = mainItem.colspan;
if (mainItem.items != undefined)
{ // All subitems of this row
for(var j = 0, lensubItems = mainItem.items.length; j < lensubItems; j++)
{ var subItem = mainItem.items[j];
Ext.applyIf(subItem, ct.defaults);
subItem = Ext.ComponentMgr.create(subItem, subItem.xtype || ct.defaultType || "textfield");
if (subItem.fieldLabel == "") subItem.labelSeparator = "";

subItem.labelWidth = subItem.labelWidth || ct.subLabelWidth || 0;
mainItem.items[j] = subItem;
subItem.colspan = subItem.colspan || 1;
cols += subItem.colspan;
ct.getForm().add(subItem);
}
this.columns = Math.max(this.columns, cols);
}
aCols[i] = cols;
}

// Set colspan
for(var i = 0, len = ct.items.length; i < len; i++)
{ var mainItem = ct.items.itemAt(i);
mainItem.colspan += this.columns-aCols[i];
}

Ext.layout.FormLayout.prototype.setContainer.apply(this, arguments);

this.currentRow = 0;
this.currentColumn = 0;
this.cells = [];
},

renderItem : function(c, position, target)
{
if (c && !c.rendered)
{

// Render mainItem
this.doRender(c, 0, Ext.get(this.getNextCell(c)), false);

// Render subitems
for (var i = 0; i < this.columns-1; i++)
{ if (c.items != undefined && i < c.items.length)
{ // Subitem available: Render it
var subItem = c.items[i];
this.doRender(subItem, 0, Ext.get(this.getNextCell(subItem)), true);
}
}

// Hide row?
if (c.hideRow) this.showRow(this.currentRow, false);

}
},

doRender : function (c, position, target, isChild)
{ // We need this in order to be able to set the labelWidth for mainitems and subitems differently
if(typeof c.labelWidth == 'number')
{ var pad = 5; // (typeof c.ownerCt.labelPad == 'number' ? c.ownerCt.labelPad : 5); // How to get the container here?
this.labelStyle = "width:"+c.labelWidth+"px;";
if (isChild) this.labelStyle += "width:"+(c.labelWidth-pad)+"px; padding-left:"+pad+"px;";
this.elementStyle = "padding-left:"+(c.labelWidth+pad)+'px;';
}

// Call Render
Ext.layout.FormLayout.prototype.renderItem.call(this, c, 0, target);
},

showRow : function (index, show)
{ var row = this.getRow(index);
if (show)
row.style.display = "";
else row.style.display = "none";
}

});

Ext.Container.LAYOUTS['autotableform'] = Ext.ux.layout.AutoTableFormLayout;

// ButtonField
// based on http://extjs.com/forum/showthread.php?t=6099&page=2 by jgarcia@tdg-i.com

Ext.namespace('Ext.ux.form');

Ext.ux.form.ButtonField = Ext.extend(Ext.form.Field,
{
defaultAutoCreate :
{
tag: 'div'
},

value : '',

onRender: function (ct, position)
{
if(!this.el)
{
var cfg = this.getAutoCreate();
if(!cfg.name)
{
cfg.name = this.name || this.id;
}
if(this.inputType)
{
cfg.type = this.inputType;
}
this.el = ct.createChild(cfg, position);
}

this.button = new Ext.Button(
{
renderTo : this.el,
text : this.text,
iconCls : this.iconCls || null,
handler : this.handler || Ext.emptyFn,
scope : this.scope || this
})
},
getValue : function()
{ return this.button.text;
},
setValue : function(value)
{ this.button.text = value;
this.value = value;
}
});

Ext.ComponentMgr.registerType("formBtn", Ext.ux.form.ButtonField );

// SimpleHtml
// based on Ext.ux.form.ButtonField

Ext.ux.form.SimpleHtml = Ext.extend(Ext.form.Field,
{
defaultAutoCreate :
{
tag: 'div'
},

value : '',

onRender: function (ct, position)
{
if(!this.el)
{
var cfg = this.getAutoCreate();
if(!cfg.name)
{
cfg.name = this.name || this.id;
}
if(this.inputType)
{
cfg.type = this.inputType;
}
this.el = ct.createChild(cfg, position);
}

this.component = new Ext.Component({
renderTo : this.el,
autoEl : { html: this.value },
scope : this.scope || this,
style : "padding-top:2px;"+(this.bodyStyle || "") // Correct the aligning with the label
})

this.hiddenName = this.name; // Make findField working

},
getValue : function()
{ return this.component.autoEl.html;
},
setValue : function(value)
{ this.component.getEl().dom.innerHTML = value;
this.value = value;
}
});

Ext.ComponentMgr.registerType("formHtml", Ext.ux.form.SimpleHtml );


Example:


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>AutoTableFormLayout Example</title>

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

<script type="text/javascript" src="AutoTableForm.js"></script>

<!-- Common Styles for the examples -->
<link rel="stylesheet" type="text/css" href="/examples/shared/examples.css" />
<script type="text/javascript">
Ext.onReady(function()
{
var myForm = new Ext.FormPanel({
title: 'My form',
renderTo: 'myformdiv',
layout: 'autotableform',
labelWidth: 80,
subLabelWidth: 60,
autoHeight: true,
width: 700,
defaults:
{
},
defaultType: 'textfield',
bodyStyle: 'padding:8px;',
items: [{ fieldLabel: '3 fields',
name: 'field0_1',
items :
[{
fieldLabel: '1. Sub',
name: 'SubItem1'
},
{
fieldLabel: '2. Sub',
name: 'SubItem2'
}]
},
{ xtype: 'formHtml',
fieldLabel: 'Some html',
value: 'hello <b>world</b>'
},
{ fieldLabel: '2 fields',
name: 'field2_1',
items :
[{ xtype: 'formBtn',
fieldLabel: 'Press',
text: 'Button'
}]
},
{ fieldLabel: 'hiddenRow',
name: 'field3_1',
hideRow: true,
items :
[{ xtype: 'formBtn',
fieldLabel: 'Press',
text: Hidden 'Button'
}]
}]
});
});
</script>
</head>

<body>
<h1>AutoTableFormLayout Example</h1>

<div id="myformdiv" style="padding-top:20px"></div>

</body>
</html>


ChangeLog:
08. August 2008 B: Added support for Ext 2.2
08. August 2008: Added default-type for subitems
08. August 2008: Added hideRow to dynamically hide a whole row in the form
18. July 2008: Added ct.getForm().add(subItem); for making subItems available through BasicForm.findField
18. July 2008: Added support for changing the html in the html-fields

cainy82
17 Jul 2008, 11:42 PM
Wow this looks really good ... I have been chasing something like this for a while.

Thanx.

moegal
25 Jul 2008, 6:42 AM
Looks like a great extension but I am getting an error when I run the example.

Ext.Container.LAYOUTS[this.layout.toLowerCase()] is not a constructor

I copied it directly in FF and am using v2.1.

Any ideas?

Marty

wuschba
28 Jul 2008, 11:26 PM
Sorry for that, it has to be:

layout: 'autotableform',

in the example-code. I just corrected it.

nanich
4 Aug 2008, 11:53 PM
Hi,
Thank you very much fo this great plugin.
I'm getting the following error, when i tried on my box.

types[config.xtype || defaultType] is not a constructor
../ext-2.1/ext-all-debug.js
Line 12086

When i remove the first item from the items array (item with fieldlabel "3 fields" and its sub items), it's working fine. Please help me in resolving this.

Thank you in advance.

wuschba
7 Aug 2008, 5:17 AM
[COLOR=Red]types[config.xtype || defaultType] is not a constructor
../ext-2.1/ext-all-debug.js
Line 12086
Works for me. Try to set the layout back to "table" and see if the error still occurs.
If it does, a small sample to reproduce the error would be fine!

Added: I found out that Firebug can issue that some types are not defined. Just turn it off till they got a new version of it and try it. Does it work then?

gif98
7 Aug 2008, 9:08 PM
Hi,
Thank you very much fo this great plugin.
I'm getting the following error, when i tried on my box.

types[config.xtype || defaultType] is not a constructor
../ext-2.1/ext-all-debug.js
Line 12086

When i remove the first item from the items array (item with fieldlabel "3 fields" and its sub items), it's working fine. Please help me in resolving this.

Thank you in advance.

i have same error,and i tried add xtype:'textfield' in sub items's cfg,the error gone,just like that
{xtype:'textfield',
fieldLabel: '1. Sub',
name: 'SubItem1'
},

wuschba
7 Aug 2008, 10:49 PM
@gif98: Thanks for this hint. I just updated the code to use the defaultType of the container or "textfield" if no type is given at all.

nanich
7 Aug 2008, 10:58 PM
gif98,
It worked. thank you very much for the quick reply.

wuschba
7 Aug 2008, 11:09 PM
I just added support f

fangzhouxing
8 Aug 2008, 12:39 AM
wuschba,thank you for sharing this great code!

elnove
11 Aug 2008, 4:09 AM
Great extention !
I'm using Ext 2.2 ,
when useing the "formHtml" type, the label is rendering ok but the html is empty on the form.

wuschba
11 Aug 2008, 8:22 AM
Thanks. There was a confusion with setValue and html. The html of a formHtml-Field should now only be set by

value : "<b>hello world</b>"

NOT with

value : "<b>hello world</b>"

I updated the code accordingly.

VinceChen
16 Aug 2008, 5:02 PM
dear wuschba:
May use this layout in "Ext.form.FieldSet"?
Because I want to use its title style. Thanks very much.

mlarese
17 Aug 2008, 4:40 AM
what about this?
http://www.extjs.com/forum/showthread.php?t=44366

fangzhouxing
13 Sep 2008, 5:02 PM
When I use the new 2.2 radiogroup field with autotableform,the whole form cannot display, anyone can help me? Thanks in advance。

fangzhouxing
9 Oct 2008, 11:18 PM
anyone?

moegal
10 Oct 2008, 4:46 AM
Thanks. There was a confusion with setValue and html. The html of a formHtml-Field should now only be set by

value : "<b>hello world</b>"

NOT with

value : "<b>hello world</b>"

I updated the code accordingly.

What is the difference?

Marty

wuschba
10 Oct 2008, 11:48 PM
Sorry, it has to be:

value : "<b>hello world</b>"

NOT with

html : "<b>hello world</b>"

emmadi
20 Nov 2008, 2:42 AM
hi thanks for the valuable code but i am getting an error ...
i.e., this.spanCells has no properties
can any body help