Skip to content

Form Validation (draft)

Marcus Krejpowicz edited this page Oct 8, 2013 · 7 revisions

Form Validation

This example shows how to do edit a model and do form validation.

1. Setting up the applicaion

Let's create a new application with rappidjs create app FormValidation and start the server inside the project dir. We should now see the application running in the browser. Once we are done we continue with creating our Model.

2. Creating the model

Let's say we have a person with the following fields:

  • firstName - required
  • lastName - required
  • address - required
  • birthdate - required
  • email - optional

Therefor we need to create a Person class under app/model which inherits from js/data/Model and define the schema.

define(["js/data/Model", "app/entity/Address"], function(Model, Address){

  return Model.inherit('app.model.Person',{
     schema: {
        firstName: String,
        lastName: String,
        address: Address,
        birthdate: Date,
        email: {
           type: String,
           required: false
        }
     }
  });

});

In the schema we can describe which fields are required and which not. The required status and the type will get validated automatically.

Now we have our person model. What we also need is the Address entity. This file we put under app/entity . The code for this entity looks like in the following snippet:

define(["js/data/Entity"], function(Entity){

  return Entity.inherit('app.entity.Address',{
     schema: {
        street: String,
        city: String,
        zipCode: String
     }
  });

});

The address entity inherits from js/data/Entity which means that it is a dependent object that can't exist alone.

// TODO: move this to "Writing validators"

3. Adding some validation logic

Adding validators

For the email field we want to add some more validation logic. Therefor we create a EmailValidator that inherits from a RegExValidator. The RegExValidator validates a field by a regular expression. We create the EmailValidator class inside the Person class and add it to the validators array of Person.

define(["js/data/Model", "app/entity/Address", "js/data/validation/RegExValidator"], function(Model, Address, RegExValidator){
   
  var EmailValidator = RegExValidator.inherit({
      defaults: {
          errorCode: 'emailError',
          regEx: /^([a-zA-Z0-9_\.\-])+@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/
      }   
  });
  
  return Model.inherit('app.model.Person',{
     schema: {
        firstName: String,
        lastName: String,
        address: Address,
        birthdate: Date,
        email: {
           type: String,
           required: false
        }
     }, 
     validators: [
       new EmailValidator({field: "email"})
     ]
  });
   
});

While instantiation we tell the Validator the field he needs to validate. In this case email.

A custom validate method

The next step is to write a validator with a custom validate method. The Validator base class offers to validate methods to override.

  • validate: function(entity, options, callback) - for asynchronous validation
  • _validate: function(entity) - for synchronous validation

The validate method allows asynchronous validation. Therefor it should return the error as second parameter of the callback. The following example shows a validator that checks if an email already exists.

define(["js/data/validator/Validator"], function(Validator){
  return Validator.inherit({
    defaults: {
       errorCode: "emailExists",
       errorMessage: "Email already exists"
    },
    validate: function(entity, options, callback){
       var email = entity.get(this.$.field); // the value to validate
       var self = this;
       // check async. for email, function is just a mock ...
       checkEmail(email, function(exists){
         var error;
         if(exists){
            error = self._createFieldError(); // creates an error object with the errorCode and errorMessage
         }
         callback(null, error);  // returns the error as second parameter
       }); 
    }
  }
});

If you don't need asynchronous validation you can override the internal _validate method. An example which checks for a given string looks like this:

define(["js/data/validator/Validator"], function(Validator){
  return Validator.inherit({
    defaults: {
       str: "someString",
       errorCode: "containsString",
       errorMessage: "Value does not contain string"
    },
    _validate: function(entity){
       var value = entity.get(this.$.field);
       if(!value || value.indexOf(this.$.str) === -1){
            return this._createFieldError();
       }
    }
  }
});

3. Creating the form

// Create the XAML and the CodeBehind file

Now we have our validators defined switch back to our application XAML and define the UI form the form.

We use plain input fields and bind the fields of the person to the value attributes.

In the code behind file we need to create an empty person instance by defining it in the defaults.

4. Calling the validate method

Now we have the form defined we need to call the validate method inside the submit handler. Calling the validate method validates the whole model and applies the errors.

Clone this wiki locally