Extjs - Form

extjs

http://superdit.com/2010/05/07/unique-field-form-validation-using-php-and-extjs/
http://application-express-blog.e-dba.com/?p=517
http://rawberg.com/wp-content/uploads/ExtJS-Forms.pdf
http://www.sencha.com/learn/Tutorial:Basic_Login

How to create a form using the simple form layout?

Ext.onReady(function() {
    new Ext.form.FormPanel({
        width: 400,
        height: 300,
        frame: true,
        bodyStyle: 'padding:10px',
        title: 'Form Title',
        defaults: {width: '100%'},
        labelAlign: 'top',
        method: 'POST',
        url: 'formtester.php',
        buttonAlign: 'center',
        buttons: [
            {
                text: 'Save',
                handler: function(btn, eventObj) {
                    var formPanel = btn.findParentByType('form');
                    var form = formPanel.getForm();
                    if (form.isValid()) {
                        form.submit({
                            clientValidation: true,
                            failure: function(form,action) {},
                            success: function(form,action) {},
                            waitMsg: 'Processing',
                            waitTitle: 'Status'
                        });
                    }
                }
            }
        },
        items: [
            {
                xtype: 'textfield',
                fieldLabel: 'Enter Password',
                name: 'enter_password',
                id: 'enter_password',
                inputType: 'password',
                maxLength: 8,
                maxLengthText: 'Password must contains at least 8 characters'
            },
            {
                xtype: 'textfield',
                fieldLabel: 'Confirm Password',
                name: 'enter_password',
                id: 'enter_password',
                inputType: 'password',
                maxLength: 8,
                maxLengthText: 'Password must contains at least 8 characters'
            },
            {
                xtype: 'textarea',
                fieldLabel: 'Message',
                name: 'message',
                height: 65
            }
        ],
        renderTo: Ext.getBody()
    });
});

getForm() is used to obtain the underlying Ext.form.BasicForm. We use the boolean value returned from isValid() to determine if the form should be submitted. When the form input has been validated, and we're ready to submit it to the server, we call the submit method on the instance of Ext.form.BasicForm. The submit method automatically creates an instance of Ext.form.Action.Submit which accepts a number of configuration options. clientValidation ensures that the form is not submitted unless all the fields pass client-side validation checks.

For the success and failure handler, Ext.form.Action.Submit is designed to accept a JSON response back from the server. The response needs to contains at least one key labeled 'success' with it's value set to true or false. You can also pass back an errors object containing additional server side error information your client code can take action on:

{
    success: false,
    errors: {
        email: "Cannot find matching email address"
    }
}

In the event of a failure condition, you can use Ext.form.Action object (passed into your failure handler function) to access additional information including failureType, and result data. If we wish to display the field label above the field, use labelAlign:top. If we wish to display the field label on the left side of the field, use labelAlign:left. This example creates the form object and render into the body of the page immediately using renderTo configuration option.

Multi-Column Form Layout:

Ext.onReady(function() {
    new Ext.form.FormPanel({
        width: 430,
        height: 330,
        frame: true,
        bodyStyle: 'padding:5px',
        title: 'Multi-Column Form Layout',
        labelAlign: 'top',
        items:[
            {
                layout: 'column',
                border: false,
                items:[
                    {
                        columnWidth: .5,
                        layout: 'form',
                        border: false,
                        bodyStyle: 'padding-right: 10px',
                        defaults: {width: '100%'},
                        items: [
                            {
                                xtype: 'textfield',
                                fieldLabel: 'First Name',
                                name: 'firstName'
                            },
                            {
                                xtype: 'checkboxgroup',
                                fieldLabel: 'Product Edition',
                                columns: 3,
                                items: [
                                    {boxLabel: 'Lite', name: 'product-edition'},
                                    {boxLabel: 'Pro', name: 'product-edition'}
                                ]
                            }
                        ]
                    },
                    {
                        columnWidth: .5,
                        layout: 'form',
                        border: false,
                        defaults: {width: '100%'},
                        items: [
                            {
                                xtype: 'textfield',
                                fieldLabel: 'Last Name',
                                name: 'lastName'
                            },
                            {
                                xtype: 'radiogroup',
                                fieldLabel: 'Preferred Contact Method',
                                columns: 3,
                                items: [
                                    {boxLabel: 'Email', name: 'contact-method', checked:true},
                                    {boxLabel: 'Phone', name: 'contact-method'}
                                ]
                            }
                        ]
                    }
                ]
            },
            {
                xtype: 'htmleditor',
                fieldLabel: 'Message',
                width: '100%',
                height: 150,
                enableSourceEdit: false,
                enableFont: false
            }
        ],
        renderTo: Ext.getBody()
    });
});

In this example, we use a panel with layout of 'column' to create 2 columns, and to give each column the same width, we set columnWidth to .5. Inside each column, we use the layout of 'form' to control the layout of form components.

The columns property is set to 3 to distribute the available space into 3 columns. Even though there are only 2 checkboxes, using 3 columns here produces a cleaner result.

Form Validation:

Form validation can be achieved with Ext JS using a few different approaches from simple configuration options to regular expressions and custom validation functions.

Initializing QuickTips:

Ext.QuickTips.init();

Validation using maxLength and minLength:

{
    allowBlank: false,
    blankText: 'This field cannot be empty',
    minLength: 2,
    minLengthText: 'Please enter more than 2 characters',
    maxLength: 20,
    maxLengthText: 'Maximum 20 characters'
}

Using vtype:

{
    vtype: 'email',
    vtypeText: 'Invalid email format.  Email must be of the form user@domain.com'
}

Controlling where validation message (icon) is displayed:

defaults: { msgTarget: 'side' }

Using maskRe, regex, and regexText:

{
    xtype: 'textfield',
    maskRe: /[a-z0-9_]/i,
    regex: /^[a-zA-Z0-9_]+$/,
    regexText: 'Only alphanumeric characters allowed'
}

Validation messages are displayed as tooltip message using Ext.QuickTips. Initializing QuickTips is required.

The vtype configuration option specifies which validation function will be applied to the field.

Validation types in ExtJS includes alphanumeric, numeric, URL, and email. You can extend this feature with custom validation functions, and virtually, any format can be validated. The following code shows how you can add a custom validation type for JPG and PNG files:

Ext.apply(Ext.form.VTypes, {
    Picture: function(v) {
        return /^.*.(jpg|JPG|png|PNG)$/.test(v);
    },
    PictureText: 'Must be a JPG or PNG file'
});

If you need to replace the default error text provided by the validation type, you can do so by using the vtypeText configuration option:

{
    xtype: 'textfield',
    fieldLabel: 'Web page',
    name: 'webPage',
    vtype: 'url',
    vtypeText: 'Please enter a URL',
    anchor: '%95'
}

How to add a custom validation type to validate one field with another field?

Frequently we face scenarios where the values of two fields need to match, or the value of one field depends on the value of another field.

Ext.apply(Ext.form.VTypes, {
    password: function(val, field) {
        if (field.initialPassField) {
            var pwd = Ext.getCmp(field.initialPassField);
            return (val == pwd.getValue());
        }
        return true;
    },
    passwordText: 'What are you doing?<br/>The passwords entered do not match!'
})

and here is the declaration for the two password fields:

{
    xtype: 'textfield',
    id: 'pwd',
    fieldLabel: 'Password',
    inputType: 'password',
},
{
    xtype: 'textfield',
    id: 'pwd-confirm',
    fieldLabel: 'Confirm Password',
    inputType: 'password',
    vtype: 'password',
    initialPassField: 'pwd'
}

In the above example, notice that we can use <br/> as part of our validation message. Also notice that we can use arbitrary string as the name for our configuration option, and we can specify it along with other configuration options.

Ext.form.VTypes is a singleton object that provides and extensible way of using a function, input mask, and validation message to validate form field input. Ext.form.VTypes includes a set of built-in functions that can be used as a starting point for creating your own vtypes.

regex, regexText, and maskRe configurations demonstrate another way of achieving the same result as validating with the built-in alphaNum method of Ext.form.VTypes. Setting maskRe prevents the field from accepting keystrokes not matching the regular expression. Then the regular expression set for regex is used to validate the user input for the field. If any input gets by the input mask and does not match the regular expression set with regex, the message you set for regexText is displayed.

validateOnBlur specifies whether the field should be validated as soon as it loses focus (default to true).

validationDelayTime in milliseconds from when the user input begins until validation is initiated

validationEvent specifies the event that should initiate field validation (defaults to 'keyup')

validator: a custom validation function.

Ext.form.VTypes['alphanewVal'] =   /^[A-Za-z]*$/;
Ext.form.VTypes['alphanewMask'] = /[A-Za-z]/;
Ext.form.VTypes['alphanewText'] = 'Invalid Entry: Only alphabets are allowed.';
Ext.form.VTypes['alphanew'] = function(val) {
     return Ext.form.VTypes['alphanewVal'].test(val);
};

Ext.form.VTypes['numericposVal'] =   /^[\d]+$/;
Ext.form.VTypes['numericposMask'] = /[\d]/;
Ext.form.VTypes['numericposText'] = 'Invalid Entry: Must be in the format Ex. 1';
Ext.form.VTypes['numericpos'] = function(val){
    return Ext.form.VTypes['numericposVal'].test(val);
};

Server-side validation:

The server should return a JSON object:

{
    success: false,
    error: [
        {
            id: 'login-pwd',
            msg: 'Sorry, you have to type the magic word!'
        }
    ]
}

This JSON object contains two properties — success and errors. The success property is present both when there are problems with the validation (success: false), or when the validation was successful (success: true). The errors property is an array containing one object for each invalid field. The object in turn contains the ID of the invalid field, and the error message.

If we have a form object, how can we render it inside an existing HTML element given that we know the ID of the HTML element?

form.render(Ext.get('pageFormContainer'));

Loading Form Data:

Real-world applications usually provide a way for users to update existing information (the same form is used for collecting the data and for updating the data).

Ext.onReady(function() {
    new Ext.form.FormPanel({
        width: 430,
        height: 330,
        frame: true,
        bodyStyle: 'padding:5px',
        title: 'Multi-Column Form Layout',
        labelAlign: 'top',
        items:[
            {
                layout: 'column',
                border: false,
                items:[
                    {
                        columnWidth: .5,
                        layout: 'form',
                        border: false,
                        bodyStyle: 'padding-right: 10px',
                        defaults: {width: '100%'},
                        items: [
                            {
                                xtype: 'textfield',
                                fieldLabel: 'First Name',
                                name: 'firstName'
                            },
                            {
                                xtype: 'checkboxgroup',
                                fieldLabel: 'Product Edition',
                                columns: 3,
                                items: [
                                    {boxLabel: 'Lite', name: 'productEdition[0]', inputValue: 'lite'},
                                    {boxLabel: 'Pro', name: 'productEdition[1]', inputValue: 'pro'}
                                ]
                            }
                        ]
                    },
                    {
                        columnWidth: .5,
                        layout: 'form',
                        border: false,
                        defaults: {width: '100%'},
                        items: [
                            {
                                xtype: 'textfield',
                                fieldLabel: 'Last Name',
                                name: 'lastName'
                            },
                            {
                                xtype: 'radiogroup',
                                fieldLabel: 'Preferred Contact Method',
                                columns: 3,
                                items: [
                                    {boxLabel: 'Email', name: 'contactMethod', inputValue: 'email', checked:true},
                                    {boxLabel: 'Phone', name: 'contactMethod', inputValue: 'phone'}
                                ]
                            }
                        ]
                    }
                ]
            },
            {
                xtype: 'htmleditor',
                fieldLabel: 'Message',
                width: '100%',
                height: 150,
                enableSourceEdit: false,
                enableFont: false
            }
        ],
        renderTo: Ext.getBody()
    });

    // load form data
    formPanel.getForm().load({
        method: 'GET',
        url: '/form/formData.php',
        failure: function() {
            Ext.Msg.alert('Error', 'Unable to load form data');
        },
        waitMsg: 'Retrieving form data',
        waitTitle: 'Loading...'
    });
});

The 'name' configuration option will be referenced in the data that we load from the server. The Ext.form.Action.Load class uses this key to match the field with the correct data value returned from the server.

Notice the 'name' configuration option being used for the two Ext.form.Checkbox items in the Ext.form.CheckboxGroup. The approach being used here is slightly different than traditional HTML forms where we might use the name productEdition[] without the numbers inside the array brackets. In order for Ext.form.Action.Load to automatically populate checkbox fields with the correct values, we need to explicitly number each checkbox in the array. If this approach does not work for your situation, you can alternatively set a unique name for each checkbox (productEdition-1, productEdition-2, etc). Another option would be to use the empty bracket naming convention (productEdition[]) and then manually populate the values from the server by looping through your server side data, and manually matching it with the correct Ext generated checkboxes.

We can use the same name for both Ext.form.Radio fields because only one of these will ever be set at a time. Ext.form.Action.Load will use both the name and inputValue to match the correct field with the server supplied data.

The HtmlEditor component generates HTML markup. User input from this component will automatically be encoded when the form is submit, and decoded when it is loaded back in. You will need to make sure that the data is also correctly encoded before it's sent back over the wire from your server to be loaded back into the HtmlEditor by Ext.form.Action.Load.

The formData.php file is a simple PHP script that creates a JSON data packet with the correct key value pairs:

$resultSet = Array();
$resultSet["firstName"] = "Rob";
$resultSet["lastName"] = "Dobalina";
$resultSet["contactMethod"] = "email";
$resultSet["productEdition[0]"] = "lite";
$resultSet["productEdition[1]"] = "pro";
$resultSet["message"] = '<b>Test</b> message created with the html editor.';
echo '{"success":true, "data": ' . json_encode($resultSet) . '}';

On the last line, we create a JSON strin. Setting 'success' to true confirms that the server did not detect any error (user is authorized to access this data). The 'data' key is set to the JSON encoded value of the PHP array containing the data for our form. Ext.form.Action.Load will use this data to populate our form.
http://www.packtpub.com/article/load-validate-submit-forms-ext-js-3.0-part2

Validation:

var isValid = Ext.getCmp('corpAbbreviation').isValid();
Ext.getCmp('startDt').markInvalid('This field is required');
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License