-
Notifications
You must be signed in to change notification settings - Fork 21
Form Validation (draft)
This example shows how to do edit a model and do form validation.
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.
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"
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".
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 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();
}
}
}
});
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.