views:

88

answers:

2

Hi, I am having a bit of trouble adding/removing fields to/from an ExtJS form. My use case is as follows:

Provide a set of radio buttons on the form. Depending on which radio button is selected, show a different set of form fields.

I am not all that familiar with ExtJS, but what I am doing is caching the fields that are to be added/removed and adding/removing them from the form when the radio button change event is fired. Here is a simplified version of my code:

var textFieldA = new Ext.form.TextField({
    fieldLabel: 'Text Field A',
    name: 'text_field_a',
    allowBlank: false
});

var textFieldB = new Ext.form.TextField({
    fieldLabel: 'Text Field B',
    name: 'text_field_b',
    allowBlank: false
});

var form = new Ext.FormPanel({
    autoScroll: true,
    bodyStyle: 'padding: 5px 5px 0',
    border: false,
    frame: true,
    layout: 'form',
    items: [{
        xtype: 'fieldset',
        fieldLabel: 'Fieldset',
        autoHeight: true,
        items: [{
            xtype: 'radiogroup',
            fieldLabel: 'Show text field',
            columns: 1,
            vertical: true,
            items: [
                {
                    xtype: 'radio',
                    boxLabel: 'Show field a',
                    name: 'field_to_show',
                    inputValue: 'a'
                },
                {
                    xtype: 'radio',
                    boxLabel: 'Show field b',
                    name: 'field_to_show',
                    inputValue: 'b'
                }
            ],
            listeners: {
                'change': {
                    fn: function(radioGroup, selectedRadio) {
                        switch (selectedRadio.getGroupValue())
                        {
                            case 'a':
                                radioGroup.findParentByType('fieldset').remove(textFieldB);
                                radioGroup.findParentByType('fieldset').add(textFieldA);
                                break;
                            case 'b':
                                radioGroup.findParentByType('fieldset').remove(textFieldA);
                                radioGroup.findParentByType('fieldset').add(textFieldB);
                                break;
                        }
                        radioGroup.findParentByType('fieldset').doLayout();
                    }
                }
            }
        }]
    }]
});

form.render('container');

This works the first time each radio is selected, but subsequent selections do not work as I would expect. In Firefox, a JavaScript error is raised:

Operation is not supported" code: "9 [Break on this error] return !!(p.compareDocumentPosition(c) & 16); in ext-base-debug-w-comments.js

In Chrome, only the labels will be added to the form.

Is the way I am expecting this to work incorrect?

A: 

I wouldnt necessarily take the approach of adding/removing the fileds- why not give each field an id (also good practice for form fields) using:

id:'fieldname'

Then either hide/show the field as appropriate using:

Ext.getCmp('fieldname').hide()
Ext.getCmp('fieldname').show()
Ergo Summary
They will still be submitted though no? Unfortunately, some of the fields would have the same name (due to how this is processed on the server side).
rr
Have you thought about using fieldsets?
Ergo Summary
A: 

I've written a very similar form. If the only common element is the radio group, here's what I suggest:

Create an outer Container that contains the RadioGroup, then a subcontainer with a CardLayout. Each child of that card layout contains a form with the fields for the different states of the RadioGroup. Add listeners to the RadioGroup so when the selection changes, you change the active item in the card container.

Basic code to get you started from when I did this:

OuterForm = Ext.extend(Ext.Container, {
    initComponent: function() {
        Ext.apply(this, {
            layout: "vbox",
            layoutConfig: { align: "stretch" }
        });
        this.items = [{
            xtype: "container",
            layout: "form",
            items: [{
                xtype: "radiogroup",
                fieldLabel: "Form to fill out",
                ref: "../../formSelector",
                items: [{
                    name: "type",
                    inputValue: "1",
                    boxLabel: "Form 1"
                }, {
                    name: "type",
                    inputValue: "2",
                    boxLabel: "Form 2"
                }],
                listeners: {
                    scope: this,
                    change: function(rg, checkedItem) {
                        this.formContainer.layout.setActiveItem(parseInt(checkedItem.inputValue));
                    }
                }
            }]
        }, {
            xtype: "container",
            layout: "card",
            flex: 1,
            ref: "formContainer",
            items: [{
                xtype: "form1"
            }, {
                xtype: "form2"
            }]
        }];

        OuterForm.superclass.initComponent.call(this);
    }
});

Not tested for typos/bugs, but just set a height for the outer form, create your form1 and form2 xtypes and it should work.

If you need all fields part of the same form, make OuterForm extend FormPanel instead of defining form1 and form2 as independent FormPanels.

divestoclimb