PDA

View Full Version : [2.2] Dynamic form fields



arnold
6 Nov 2008, 2:29 PM
Ever wanted to just dynamically add a few additional fields to your form.
Or maybe even set an array of values like



field.setValues(['Bill','Stephen','William'])
fieldSet.setValues([{'resource/first' : 'Bill','resource/last' : 'Joy'},{'resource/first' : 'Stephen'},{'resource/last' : 'Wolfram'}]);


or even



panel.getForm().setValues({
'first' : ['Bill','Stephen','William']
,'fs' : [{'resource/first' : 'Bill','resource/last' : 'Joy'}
,{'resource/first' : 'Stephen'},{'resource/last' : 'Wolfram'}
]
});


And expect additional fields to be created on the fly and whenever they are required.
A small extension and a few plugins were created to make this possible.

Just unzip the attached file into the examples directory and you should be able to start using it.
The code is tested in both FF & IE

Add the configuration options as specified below, or reuse the example that's part of the zip file, and you done.


var panel = new Ext.FormPanel({
labelWidth: 75,
width: 450,
defaults: {width: 230},
title :'Simple Form',
frame:true,
renderTo : document.body,
defaultType: 'textfield',
plugins:[Ext.ux.plugins.DynamicPanel],
items: [{fieldLabel: 'First Name',
name: 'first',
dynamic:true,
maxOccurs:5 // amount of occurences of first name allowed
},.....
{fieldLabel: 'Birth date',
name: 'birthDate',
allowBlank:false,
xtype:'datefield',
dynamic:true
},
{ xtype : 'fieldset',
title: 'Just a set of fields',
name : 'fs',
autoHeight:true,
width: 300,
defaultType: 'textfield',
plugins:[Ext.ux.plugins.DynamicFieldSet],
maxOccurs : 3,
items :[{fieldLabel: 'First Name', name: 'resource/first', width : 150},
{fieldLabel: 'Last Name', name: 'resource/last', width : 150}]
}],
buttons: [{text: 'Save'},{text: 'Cancel'}]
});


update 14032009 : this implementation is deprecated, read dynamic form fields (http://extjs.com/forum/showthread.php?t=62774) for the latest version

denkoo
6 Nov 2008, 10:00 PM
Very interesting :)

I regret only one thing when we reach max number iteration alowed, you simulate an error on first field or first field on a fieldset... But it's not an error, will be most interesting to have warning message like notice extension or other.. but not a permantly message..

Other, I have an allowBlank=false on first child or vtype... your message can mask this important information for User and for program...

When the Max iteration number was reach and you print your alert... if I check form.isValid(), form return false ???

I will be enjoy to find this new possibility .thanks for sharing again :)

arnold
7 Nov 2008, 12:36 AM
Thanks for your positive feedback. The latest version fires an event when you reach max number iterations.

denkoo
7 Nov 2008, 2:47 PM
Effectively... best choice :)

brenda
11 Nov 2008, 6:48 PM
This is good and is exactly what I want. However, I am wondering how to send the set of data to the server-side after I've click send. :s

Anyone can help on that?

funfan34
11 Nov 2008, 8:04 PM
Hi,

I am new to extjs. Can someone tell me why this does not work :

var combo = Ext.get('id-of-Combobox-proj-app');
var value = combo.getValue();
var record = combo.findRecord(combo.valueField || combo.displayField, value);
var index = combo.store.indexOf(record);


But the following works:

var combo = Ext.getCmp('id-of-Combobox-proj-app');
var value = combo.getValue();
var record = combo.findRecord(combo.valueField || combo.displayField, value);
var index = combo.store.indexOf(record);


What's the difference and when should we use Ext.getCmp and Ext.get ?

brenda
11 Nov 2008, 9:36 PM
Hi funfan34,
I think reading this API on this will give you some info on the differences between Ext.getCmp & Ext.get :)

http://extjs.com/deploy/dev/docs/?class=Ext

Hope this helps

arnold
14 Nov 2008, 7:44 AM
This is good and is exactly what I want. However, I am wondering how to send the set of data to the server-side after I've click send. :s

Anyone can help on that?

This actually depends on you your prefered language & framework.
Nowadays I use a REST based webservice that handles all my server side communication
The webservice is called by using the Ext.Ajax.request method.

brenda
18 Nov 2008, 9:42 PM
Hi arnold,
I understand that the data sorting/ spliting part depends on the language and framework used at my server side end.

I am currently having problem concatenating the input that a user have inserted via the clone fields.

I've tried many ways to get concatenate the input in my textfield but none work.
(My server-side only recognize the first set of input)

Here's how my code looks like:

var commentFieldset = new Ext.form.FieldSet({
xtype : 'fieldset',
title: 'Comment set',
name : 'fs',
autoHeight:true,
//width: 300,
anchor: '90%',
defaultType: 'textfield',
labelSeparator: ' ',
plugins:[Ext.ux.plugins.DynamicFieldSet],
maxOccurs : 8,
items :[{
xtype: 'textarea',
fieldLabel: 'Comment <font color="#FF0000">*</font>',
id: 'comment',
name: 'comment',
anchor: '90%',
listeners: { // to test what's in my textfield
blur: function(b){
//alert('Value of textfield ' + b.getValue());
var addStr = '';
addStr = addStr + b.getValue();
alert('Value of textfield ' + addStr);
}
}
},{
xtype: 'datefield',
fieldLabel: 'Post date <font color="#FF0000">*</font>',
allowBlank: false,
name: 'commentDate',
format:'d/m/Y',
anchor: '60%'
},{
fieldLabel: 'Author <font color="#FF0000">*</font>',
allowBlank: false,
name: 'author',
anchor: '90%'
}]
});

I am wondering how can I make the duplicate textfields within a fieldset unique before I pass these data to the severside.

PS: if there's a better alternative, show me how to do that :)

(Serverside is using Spring framework with Hibernate, language used is Java)

arnold
19 Nov 2008, 12:02 AM
Just as a starter.

To extract the values. Take a look at formPanel.getForm().getValues().
Usually I extract these values on submit of the form.

Currently I am using spring, hibernate, json-lib and jersey as part of my J2EE backend.
To communicate the values to your backend. Take a look at Ext.Ajax.request.
The call contains an argument jsonData. Encode and decode your form
values by using Ext.util.JSON.encode and Ext.util.JSON.decode.
You can use json-lib to encode/decode the json format into a java bean.

brenda
19 Nov 2008, 5:29 PM
Just as a starter.

To extract the values. Take a look at formPanel.getForm().getValues().
Usually I extract these values on submit of the form.

Currently I am using spring, hibernate, json-lib and jersey as part of my J2EE backend.
To communicate the values to your backend. Take a look at Ext.Ajax.request.
The call contains an argument jsonData. Encode and decode your form
values by using Ext.util.JSON.encode and Ext.util.JSON.decode.
You can use json-lib to encode/decode the json format into a java bean.
Seems like we have a similar backend :)

Btw, are you saving all the values retrieved from ExtJS to the same table in the DB or to different tables?

mystix
19 Nov 2008, 10:35 PM
good job on this plugin thus far. =D>

some things to note though:

missing var declarations on the following lines:


Ext.override(Ext.form.Field, {
clone : function(len) {
panel = this.ownerCt;

// ... ... ...
}
});

Ext.override(Ext.form.FieldSet, {
clone : function(len) {
panel = this.ownerCt;

// ... ... ...
},

setValues : function (array) {
var panel = this.ownerCt;
this.clone(array.length);
fss = panel.find('name', this.name);

// ... ... ...
}
});


the following override can be simplified:


Ext.override(Ext.form.BasicForm, {
/* original
findFieldSet : function(name) {
var fs;
Ext.each(this.panel.find('name', name), function(cfs) {
if (cfs.xtype && cfs.isXType('fieldset')) {
fs = cfs;
return;
}
});
return fs;
}
*/

// simplified
findFieldSet : function(name) {
return this.panel.findBy(function(cmp) {
return cmp.isXType('fieldset') && cmp.name == name;
})[0];
}
});


plus / minus icons for Fields could use a mouseover effect. i recommend using the original cls:'x-tool x-tool-plus' (or minus class) instead of your custom css icon classes, plus the following override:


Ext.override(Ext.form.Field, {
markAddDynamic : function() {
if (!this.rendered || this.preventMark) { // not rendered
return;
}
this.el.addClass(this.dynamicClass);

if (!this.dynamicIcon) {
var elp = this.getDynamicCt(this.el);
if (!elp) { // field has no container el
return;
}
this.dynamicIcon = elp.createChild({cls:'x-tool x-tool-plus'});
this.dynamicIcon.addClassOnOver('x-tool-plus-over');
this.dynamicIcon.on('click', this.dynamicAddClick, this);
}
this.alignDynamicIcon();
this.on('resize', this.alignDynamicIcon, this);
},

markRemoveDynamic : function() {
if (!this.rendered || this.preventMark) { // not rendered
return;
}
this.el.addClass(this.dynamicClass);

if (!this.dynamicIcon) {
var elp = this.getDynamicCt(this.el);
if (!elp) { // field has no container el
return;
}
this.dynamicIcon = elp.createChild({cls:'x-tool x-tool-minus'});
this.dynamicIcon.addClassOnOver('x-tool-minus-over');
this.dynamicIcon.on('click', this.dynamicRemoveClick, this);
}
this.alignDynamicIcon();
this.on('resize', this.alignDynamicIcon, this);
}
});

follwing which clone.css may be reduced to just:


/** IE fix for messed up Ext.ux.plugin.DynamicFieldSet's tool icon */
.ext-ie .x-fieldset legend{width:130px;}

note: YMMV on IE though -- i got slightly clunky behaviour in IE6 when the mouseover class is applied.

IMHO, Field-level error icons look better when placed after the plus / minus icons. the following override achieves this effect:


Ext.override(Ext.form.Field, {
alignDynamicIcon : function() {
this.dynamicIcon.alignTo(this.wrap || this.el, 'tl-tr', [2, 3]);
},

alignErrorIcon : function() {
this.errorIcon.alignTo(this.el, 'tl-tr', [2 + this.dynamicIcon? this.dynamicIcon.getWidth() + 4 : 0, 0]);
}
});

Ext.override(Ext.form.TriggerField, {
alignErrorIcon : function() {
this.errorIcon.alignTo(this.wrap, 'tl-tr', [2 + this.dynamicIcon? this.dynamicIcon.getWidth() + 4 : 0, 0]);
}
});



[ Result ]
http://img149.imageshack.us/img149/1715/46391612op7.png



HTH, and keep up the good work :)

arnold
20 Nov 2008, 12:48 AM
Seems like we have a similar backend :)

Btw, are you saving all the values retrieved from ExtJS to the same table in the DB or to different tables?

Different tables.

A bit more background information.
Usually I write a REST based backend for my Extjs applications.
These webservices consume and produce json.
Once that's established I use json-lib to map json onto my hibernate entities.
The values retrieved from Extjs are therefore mapped onto my hibernate entities.
Properties with multiple values are usually mapped onto collection of values
or collection of entities of hibernate. As a result values retrieved from Extjs
are usually mapped onto different tables.

arnold
20 Nov 2008, 12:57 AM
good job on this plugin thus far. =D>

Many thanks for your indepth response.
I will introduce the changes you've proposed.

misrasandeep
1 Dec 2008, 12:52 PM
Any Idea how can we make it work: Here is the code :


var names1= new Ext.form.Field({fieldLabel: 'Viewers,
name: 'txtProxies',
dynamic:true,
maxOccurs:5,
labelSeparator: '',
width: 250
});
var names2= new Ext.form.Field({fieldLabel: 'Editors',
name: 'txtEditors',
labelSeparator: '',
width: 250
});
var fieldSet = new Ext.form.FieldSet({
xtype : 'fieldset',
title: 'Contacts',
name : 'fsContacts',
autoHeight:true,
width: 800,
defaultType: 'textfield',
items: [ names1,names2]
});
var contactDetailsForm = new Ext.FormPanel({
id : 'test',
labelAlign: 'top',
width: 850,
title :'Editing Online',
frame:true,
renderTo : Document.body,
defaultType: 'textfield',
plugins:[Ext.ux.plugins.DynamicField],
items: [fieldSet]
});
It shows me 2 fields inside the field set but they dont have plus sign against them, also if I use coulmn layout inside the fieldset, only one field gets rendered, without the label.
Any suggestions ? am I doing anything wrong here ?

arnold
1 Dec 2008, 1:03 PM
{xtype : 'fieldset',
title: 'Details',
defaults:{bodyStyle:'padding:10px'},
border : true,
autoHeight:true,
plugins:[Ext.ux.plugins.DynamicField],
items :[
{fieldLabel: 'First Name',
name: 'value',
nameSpace: 'firstNames',
xtype:'textfield',
labelSeparator : '',
maxOccurs : 2,
dynamic: true,
width: 150
}]}

misrasandeep
1 Dec 2008, 1:32 PM
{xtype : 'fieldset',
title: 'Details',
defaults:{bodyStyle:'padding:10px'},
border : true,
autoHeight:true,
plugins:[Ext.ux.plugins.DynamicField],
items :[
{fieldLabel: 'First Name',
name: 'value',
nameSpace: 'firstNames',
xtype:'textfield',
labelSeparator : '',
maxOccurs : 2,
dynamic: true,
width: 150
}]}

Hi ,
Thanks for prompt reply , but I am still not able to construct a form with dynamic fields inside a fieldset. Though from your example fieldset itself can be made dynamic as a whole , easily.
When I tried above example, I see form getting rendered twice.
I am using the zip files on the first page of this thread, are they latest ? also in your code you mentioned an attribute namespace, which is not there in any sample code....Am I missing something here,

Dan1357
24 May 2009, 6:32 AM
After reading through the above posts, I am still at a loss of how to retrieve the clone fields on submit. When the form is submitted all of the regular fields and the last instance of the cloned field is sent, but the other clones are not sent.




{
xtype:'fieldset'
,title: 'textarea'
,autoHeight:true
,defaults: {width: 210}
,defaultType: 'textfield'
,nameSpace:'person'
,plugins:[Ext.ux.plugins.DynamicFieldSet]
,maxOccurs : 10
,items :[{
fieldLabel:'Text Area'
,xtype:'textarea'
,name: 'cloned'
,anchor:'100%'
},
{
xtype:'checkbox'
,fieldLabel:'checkbox'
,name:'checkbox'
,store:['YES', 'NO']
}
]

}

] // center top form items
, buttons: [{
text: 'Save',
handler: function(){
Ext.getCmp('reference-entry').getForm().submit({
url: 'action.php?action=save',
failure: function(pd, action){
Ext.MessageBox.alert('Failed: ');
},
success: function(pd, action){
Ext.MessageBox.alert('Success: ');

},
formPanel.getForm().getValues().
waitMsg: 'Saving Data...'
});
}
}

Dan1357
25 May 2009, 9:25 AM
This must be something others have come across already.

ridhopahwanae
18 May 2010, 3:04 AM
Thanks for sharing.... I like it

pratik016
12 Oct 2010, 5:43 AM
Hey,

Good Work and thanks for post this examples.
I need some help. All dynamic fields are generated. But I want newly generated field in specific location. And rederTo/render is catch the error.
I have many 'fieldset' .. and need to add new generated field at the end...

:)