PDA

View Full Version : [2.2] Ext.ux.plugins.FormPanel.AlternatePanels Add variable Field Sets to Forms



BitPoet
5 Mar 2009, 5:13 AM
I've recently had the requirement to make parts of a form changeable on the fly, i.e. display only varying subsets of the fields. The specific case were address schemes where, depending on the country, fields like zip code had to be hidden while others had to be added. I also wanted the form to only transmit visible fields on a regular submit().

As the fields, though bearing the same name, could be quite different in behaviour (also requiring different input validators), it became clear that I needed different field instances with different ids but identical names.

I thought about using a card layout and disabling all but one card at any time, but this would have required to nest panels inside the card panel inside the form panel, and that just didn't feel right.

So I came up with this plugin. It can either be directly bound to a combo box with the indexes of the 'fieldset' panels as its values, or you switch between the fieldsets manually my calling activateFieldPanel(index) on the parent FormPanel.

Changing a field in one of the panels will also change the identically named fields in all alternative panels.



/**
* @class Ext.ux.plugins.FormPanel.AlternatePanels
* @extends Ext.util.Observable
*
* A plugin class for Ext.form.FormPanel
*
* Lets you add multiple alternative panels with form fields that
* bear identical names. Depending on a combo box specified in
* the constructor, only one of the panels is shown at each time.
*
* If the combo changes its selected value, the panel identified
* by its value is shown instead. Any changes to a form field in
* one of the panels automatically propagate to all identically
* named fields in the other panels.
*
* Only the values of the currently selected panel are transferred
* when the form is submitted.
*
* @author Chr. Winter (bitpoet@linux-config.de)
* @copyright (C) 2008 Chr. Winter
* @date 5. March 2008
* @version 1.0
*
* @license Ext.ux.tree.RemoteTreePanel.js is licensed under the terms of the Open Source
* LGPL 3.0 license. Commercial use is permitted to the extent that the
* code/component(s) do NOT become part of another Open Source or Commercially
* licensed development library or toolkit without explicit permission.
*
* <p>License details: <a href="http://www.gnu.org/licenses/lgpl.html"
* target="_blank">http://www.gnu.org/licenses/lgpl.html</a></p>
*
*/

Ext.ns('Ext.ux.plugins.FormPanel');

Ext.ux.plugins.FormPanel.AlternatePanels = function(config) {
Ext.ux.plugins.FormPanel.AlternatePanels.superclass.constructor.call(this);
this.config = config;
};

Ext.extend( Ext.ux.plugins.FormPanel.AlternatePanels, Ext.util.Observable, {
// local options
config: false,
parentform: false,
panels: [],

// config options
/**
* @cfg {Integer} position the position of the panels in the
* FormPanel's items collection.
*/

/**
* @cfg {String} chooser The id of the combo box that switches
* between panels.
*/

/**
* @cfg {Object} panelcfg Config options that should be applied
* to each of the panels (for the sub panel to blend into the
* form, you'll want to set border: false here).
*/

/**
* @cfg {Array} panels The definitions for the panels. Each entry
* is itself an array of config objects for the panel's fields.
*/

/**
* The init method for the plugin that is automatically called
* by the form.
*
* @param {Ext.form.FormPanel} parentform
* @public
*/
init: function(parentform) {
this.parentform = parentform;
this.parentform.activateFieldPanel = this.activateFieldPanel.createDelegate(this);
for( var i = 0; i < this.config.panels.length; i++ ) {
var pcfg = Ext.apply({}, this.config.panelcfg, {
items: this.config.panels[i],
ownerCt: this.parentform
});
if( i != 0 ) {
pcfg.disabled = true;
pcfg.hidden = true;
}
var newpnl = new Ext.Panel(pcfg);
this.panels.push(newpnl);
var posidx = this.config.position + i;
this.parentform.items.insert( posidx, newpnl );
newpnl.items.each( function(e) {
if( e.setValue ) {
e.on( 'change', this.propagateChange.createDelegate(this) );
}
}, this);
}
if( this.config.chooser ) {
parentform.on( 'render', this.activateChooser.createDelegate(this) );
}
},
/**
* Adds the select handler to the combo box that switched between
* panels.
*
* @private
*/
activateChooser: function() {
Ext.getCmp(this.config.chooser).on( 'select', this.swapPanel.createDelegate(this) );
},
/**
* Manually activate the given panel
*
* @param {Integer} idx
* @public
*/
activateFieldPanel: function(idx) {
this.swapPanel(idx);
},
/**
* Switch between panels.
* You can also call this method on the parent form's object.
*
* @param {Ext.form.ComboBox|Integer} combo
* @private
*/
swapPanel: function(combo) {
var selitem = combo;
if( Ext.type(combo) == 'object' ) {
selitem = combo.getValue();
}
for( var i = 0; i < this.panels.length; i++ ) {
var curritem = this.panels[i];
if( selitem == i ) {
curritem.enable();
curritem.show();
curritem.items.each(function(i) { i.enable(); });
} else {
curritem.disable();
curritem.hide();
curritem.items.each(function(i) { i.disable(); });
}
}
},
/**
* Propagate changes in one field to all its namesakes in the
* other panels.
*
* @param {Ext.form.Field} fld
* @param newval
* @private
*/
propagateChange: function(fld, newval) {
for( var i = 0; i < this.panels.length; i++ ) {
var pnl = this.panels[i];
if( pnl.items ) {
var pnlfield = pnl.items.filter( 'name', fld.name ).first();
if( pnlfield ) {
pnlfield.setValue( newval );
}
}
}
}
});
// EOF Ext.ux.plugins.FormPanel.AlternatePanels;
To use the plugin, it needs the following parameters in the config object:
position: The position in the FormPanel's items collection where it should appear
panelcfg: The config parameters for each panel (e.g. border, layout)
chooser: [optional] The combo box to bind to
panels: an array containing of arrays of field configsHere's a config example:


var fldconfigs = new Ext.ux.plugins.FormPanel.AlternatePanels({
position: 1,
panelcfg: { layout: 'form', border: false },
chooser: 'cbAddrSet',
panels: [
[
{
xtype: 'textfield',
id: 'c0_name1',
name: 'name_1',
fieldLabel: 'Surname',
},
{
xtype: 'textfield',
id: 'c0_name2',
name: 'name_2',
fieldLabel: 'Givenname',
}
], [
{
xtype: 'textfield',
id: 'c1_name1',
name: 'name_1',
fieldLabel: 'Nachname',
},
{
xtype: 'textfield',
id: 'c1_name2',
name: 'name_2',
fieldLabel: 'Vorname',
},
{
xtype: 'textfield',
id: 'c1_name3',
name: 'name_3',
fieldLabel: 'Namenszusatz',
},
{
xtype: 'textfield',
id: 'c1_plz_str',
fieldLabel: 'PLZ',
name: 'plz_str'
},
{
xtype: 'textfield',
id: 'c1_ort',
fieldLabel: 'Ort',
name: 'ort'
}
]
]
});
And a usage example for the above config:


var stAddrSets = new Ext.data.SimpleStore({
fields: [
{ name: 'value', id: 'value' },
{ name: 'key', id: 'key' }
]
});
stAddrSets.loadData([
[0, 'Generic'],
[1, 'German']
]);

var wndForm = new Ext.form.FormPanel({
id: 'wndForm',
title: 'Test Form',
width: 600,
height: 500,
renderTo: document.body,
deferredRender: false,
hideMode: 'offsets',
url: '/submitform.php',
items: [
new Ext.form.ComboBox({
id: 'cbAddrSet',
fieldLabel: 'Select Address Scheme',
triggerAction: 'all',
hiddenName: 'addrSchemaSel',
displayField: 'key',
valueField: 'value',
forceSelection: true,
editable: false,
store: stAddrSets,
mode: 'local',
autoLoad: true
}),
new Ext.Button({
id: 'btnSave',
text: 'Save Changes',
handler: function() {
Ext.getCmp('wndForm').getForm().submit();
}
}),
new Ext.Button({
id: 'btnSwitch',
text: 'Switch to second scheme',
handler: function() {
Ext.getCmp('wndForm').activateFieldPanel(1);
Ext.getCmp('cbAddrSet').setValue(1);
}
})
],
plugins: [fldconfigs]
});