10

This article by Sencha covers how to use the built in validation rules (presence, length, format, inclusion, exclusion) and mentions that adding custom rules is easy, but doesn't ever explain how to do it. I've googled high and low and read the sencha docs, but I can't find anything on how to do it. Any Ideas?

http://www.sencha.com/learn/using-validations-and-associations-in-sencha-touch

micmcg
  • 2,372
  • 18
  • 16

4 Answers4

8

I think it's one of the slight errors in the documentation. I got them to work by adding some code

if (Ext.data) {
    Ext.data.validations.custom = function (config, value) {
        if (config && Ext.isFunction(config.fn)) {
            //this should be the model
            if (config.self) {
                return config.fn.call(config.self, value);
            } else {
                return config.fn(value);
            } 
        }
        else 
        {
            return false;
        }
    };
    Ext.data.validations.customMessage = "Error";
}

Then to add a validation to a model, add an object to the model's validations array with type set to 'custom', e.g.

{ 
    type: 'custom', field: 'SomeField', message: "Your field is bad",
    fn: function (SomeFieldValueForThisInstance) {
       //Add some validation code.  The this pointer is set to the model object
       //so you can call this.get("SomeOtherFieldToCheck")
       //or any other instance method

       //if the field is good
       return true;
       //else
       return false;
    }
}

Update: @salgiza was right, there's a few steps I forgot to mention in order to set the 'this' pointer correctly. If you look in the sencha touch code you'll see that at the end of Ext.data.Model's constructor it checks to see if there's an init function defined on the object, and if so, calls it

        if (typeof this.init == 'function') {
            this.init();

After you define your model you can add an init function to the prototype. In the function, iterate over the validations for the object and add a reference to this. This step should be done before any of the models are created.

    YourModel.prototype.init = function () {
        var i, len;
        if (this.validations) {
            for (i = 0, len = this.validations.length; i < len; i++) {
                this.validations[i].self = this;
            }
        }
    };

Then in the custom validation function above, just check if the config has a self pointer and if it does, call it with self. I've edited the code above to use self.

Note: I don't see the Model's init function documented, so if sencha gets rid of it, you'll have to add the this pointer to the model's validations some other way.

Sorry if this caused confusion for anybody.

Jason Freitas
  • 1,587
  • 10
  • 18
  • I don't know if it's changed since you posted your answer, but in Sencha 1.1.1 the validation scope is the validation object, so there doesn't seem to be any way to get other values in the model, except for the one being validated (this.get does nothing, as "this" is not the model). – salgiza Nov 14 '11 at 12:17
  • 1) You have too many `else` branches. 2) Where does `YourModel.prototype.init` go? This makes no sense. – Sarah Vessels Feb 28 '12 at 16:20
  • 1
    @SarahVessels 1. You're right. I was missing a } for the second else block. Sorry about that. 2. YourModel.prototype.init can go anywhere as long as you execute it after you've declared your model. I use RequireJS to manage my dependencies so I include the module that adds to the prototype after I've included my models. – Jason Freitas Feb 28 '12 at 23:09
  • @JasonFreitas thanks for the clarification! The part that threw me off about `YourModel.prototype.init` was "This step should be done before any of the models are created." – Sarah Vessels Feb 29 '12 at 14:34
3

i think the easiest way to add complex custom validations to your model is to overwrite the validate method. see below, due to the parent call, it supports the builtin validation types.

validate: function() {
    var me = this;
    var errors = this.callParent(arguments);

    /* custom complex validations here */
    if(true !== me.get('checkOne') &&
       true !== me.get('checkTwo') &&
       true !== me.get('checkThree')) {
       errors.add(Ext.create('Ext.data.Error', {
                    field  : 'checkOne',
                    message: 'Choose at least one check, e.g. checkOne'
                }));
    }

    return errors;
}
casdero
  • 41
  • 1
2

I've slightly adapted the code from Jason for sencha touch 2 (since validations is now in the config property of the model). I suggest creating a base class from which all your other model classes would inherit. Then, once you've done that, you can use jason's technics for adding custom validations in Ext.data.validations singleton.

Ext.define('MyApp.model.CustomModelBase', {
    extend: 'Ext.data.Model',

    //adding an initializer to let custom validators access "self"
    init : function () {
        var i, len;
        if (this.config.validations) {
            for (i = 0, len = this.config.validations.length; i < len; i++) {
                this.config.validations[i].self = this;
            }
        }
    }
});
Ben G
  • 3,965
  • 3
  • 30
  • 34
1

needed to implement a custom validation as well, googled, also found this tomalex0/SenchaTouch-Form-Validation on github

noromamai
  • 31
  • 1
  • 3