Multiple validation: multi vtype for textfield in Ext JS 4

Multiple validation: multi vtype for textfield in Ext JS 4

Hi, in this article I will show you multiple implementation of vtype in Ext JS 4. In my previous post about custom validation I used PIN number example because some banks do not give out numbers where all digits are identical (such as 1111, 2222, etc.).

Ext JS 4 Custom Validation: vtype for validating

Here I will use the same way to show you how you can do this. But it will be more real world example than previous one. Ok, I use validation to check if value is a number and characters are not identical in the PIN Number textfield.

The experimental form look like the following picture:

22-extjs4

The code look like the following lines:

Ext.define('DevJS.view.users.Add', {
    extend: 'Ext.window.Window',
    alias: 'widget.usersAdd',

    height: 225,
    width: 369,
    resizable: false,
    title: 'Add user',
    modal: true,

    initComponent: function() {
        var me = this;

        Ext.applyIf(me, {
            items: [
                {
                    xtype: 'form',
                    bodyPadding: 20,
                    title: '',
                    defaults: { // defaults are applied to items, not the container
                        allowBlank: false,
                        allowOnlyWhitespace: false,
                        msgTarget: 'side',
                        xtype: 'textfield',
                        anchor: '100%'
                    },
                    items: [
                        {
                            fieldLabel: 'Login',
                            name: 'login',
                            minLength: 4
                        },
                        {
                            fieldLabel: 'First Name',
                            name: 'firstName'
                        },
                        {
                            fieldLabel: 'Last Name',
                            name: 'lastName'
                        },
                        {
                            fieldLabel: 'Email',
                            name: 'email',
                            vtype: 'email'
                        },
                        {
                            fieldLabel: 'PIN Number',
                            name: 'pin',
                            minLength: 4,
                            maxLength: 4
                        },
                        {
                            xtype: 'button',
                            anchor: 0,
                            itemId: 'save',
                            text: 'Save'
                        },
                        {
                            xtype: 'button',
                            anchor: 0,
                            itemId: 'cancel',
                            text: 'Cancel'
                        }
                    ]
                }
            ]
        });

        me.callParent(arguments);
    }

});

The multi vtype implementation

The first file, new custom vtypes in app/lib/form/field:

Ext.define('DevJS.lib.form.field.VTypes', {

    pin: /(?!(.)\1\1).{3}/,
    digits: /[0-9]+$/,

    init: function () {
        var me = this;

        //pin number
        this.pinFn();
        //only digits
        this.digitsFn();
        //etc..
    },
    pinFn:function () {
        var me = this;

        Ext.apply(Ext.form.field.VTypes, {
            pin:function (val, field) {
                //check value
                return me.pin.test(val);
            },
            pinText: 'Characters cannot be identical'
        });
    },
    digitsFn:function () {
        var me = this;

        Ext.apply(Ext.form.field.VTypes, {
            digits:function (val, field) {
                //check value
                return me.digits.test(val);
            },
            digitsText: 'Only numbers are allowed'
        });
    }
});

To do this you have to apply a new function to the Ext.form.field.VTypes object.

//Ext.form.field.VTypes is a singleton object

//The nice way is to create a new file called VTypes.js in the lib directory

The important thing here is to use the same namespace (please use function name) in Text variable, in this case: pinText and digitsText. And your custom function result should be true (valid) or false (not valid). If you need you can initialize more vtypes in the init function.

To implement your lib file you can open DevJS.Application class (app/application.js) and add to the launch function the following line:

Ext.create('DevJS.lib.form.field.VTypes').init();

and please add to requires array the filename string:


requires: [
    'DevJS.lib.form.field.VTypes'
 ]

After that your custom vtypes should be implemented and you can use them across your application.

How to use for example two types of validation in the one textfield?

To do this you can override the default getErrors() method in the Ext.form.field.Text which is responsible for validation.

//Remmeber, overriding this class can be dangerous, especially when you change for example version of the framework, but if you sure it will not happen soon you can override the Ext.form.field.Text class

My custom method is in the following file (app/lib/form/field/override/Text.js):

Ext.define('DevJS.lib.form.field.override.Text', {
    override: 'Ext.form.field.Text',

    getErrors: function(value) {
        var me = this,
            errors = me.callSuper(arguments),
            validator = me.validator,
            vtype = me.vtype,
            vtypes = Ext.form.field.VTypes,
            regex = me.regex,
            format = Ext.String.format,
            msg, trimmed, isBlank;

        value = value || me.processRawValue(me.getRawValue());

        if (Ext.isFunction(validator)) {
            msg = validator.call(me, value);
            if (msg !== true) {
                errors.push(msg);
            }
        }

        trimmed = me.allowOnlyWhitespace ? value : Ext.String.trim(value);

        if (trimmed.length < 1 || (value === me.emptyText && me.valueContainsPlaceholder)) {
            if (!me.allowBlank) {
                errors.push(me.blankText);
            }
            // If we are not configured to validate blank values, there cannot be any additional errors
            if (!me.validateBlank) {
                return errors;
            }
            isBlank = true;
        }

        // If a blank value has been allowed through, then exempt it dfrom the minLength check.
        // It must be allowed to hit the vtype validation.
        if (!isBlank && value.length < me.minLength) {             errors.push(format(me.minLengthText, me.minLength));         }         if (value.length > me.maxLength) {
            errors.push(format(me.maxLengthText, me.maxLength));
        }

        switch(typeof vtype)
        {
            case 'string':
                if (!vtypes[vtype](value, me)) {
                    errors.push(me.vtypeText || vtypes[vtype +'Text']);
                }
                break;
            case 'object':
                Ext.Array.each(vtype, function(v){
                    if (!vtypes[v](value, me)) {
                        errors.push(me.vtypeText || vtypes[v +'Text']);
                    }
                });
                break;
        }

        if (regex && !regex.test(value)) {
            errors.push(me.regexText || me.invalidText);
        }

        return errors;
    }
});

The code for getErrors() function you can find in your framework files (ext/src/form/field/Text.js). I replaced those lines:

        if (vtype) {
            if (!vtypes[vtype](value, me)) {
                errors.push(me.vtypeText || vtypes[vtype +'Text']);
            }
        }

and added the following code:

        switch(typeof vtype)
        {
            case 'string':
                if (!vtypes[vtype](value, me)) {
                    errors.push(me.vtypeText || vtypes[vtype +'Text']);
                }
                break;
            case 'object':
                Ext.Array.each(vtype, function(v){
                    if (!vtypes[v](value, me)) {
                        errors.push(me.vtypeText || vtypes[v +'Text']);
                    }
                });
                break;
        }

Using this function allows you to add functionality to existing class. Please note that I made additional change in the line with:

errors = me.callParent(arguments),

and added the following:

errors = me.callSuper(arguments),

You can do this only when you’re using ExtJS 4.1.3 or later version. This line skip the overridden method and call the superclass implementation. You can find more info here:

Ext.Base method callSuper

Next, please add to requires array (app/application.js) the filename string:

requires: [
    'DevJS.lib.form.field.VTypes',
    'DevJS.lib.form.field.override.Text'
 ]

And the last thing, please change pin textfield configuration:


                        {
                            fieldLabel: 'PIN Number',
                            name: 'pin',
                            minLength: 4,
                            maxLength: 4,
                            vtype: ['pin', 'digits']
                        }

Now you can use multi vtype validation across your application! You can use the standard “string” way or the second one with “array” possibility.

Okay, the show time. We will check if it works. The result should look like the following pictures:

a) built-in email validation

25-extjs4

b) multi custom validation

26-extjs4

27-extjs4

c) and valid values

28-extjs4

As you can see it’s working as well. In the one of my next posts I will show you how you can pass parameters with your vtype because some of validations need parameters. Have fun and see you soon.

Comments:

Leave a Reply

Please fill all required fields


Drag circle to the rectangle on the right!

Send