Skip to content

Instantly share code, notes, and snippets.

@planetcrypton
Last active January 2, 2016 16:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save planetcrypton/3c5ec44158ef957cbaf2 to your computer and use it in GitHub Desktop.
Save planetcrypton/3c5ec44158ef957cbaf2 to your computer and use it in GitHub Desktop.
Really simple model-validation for Ember.JS (ember-cli), by extending a model with extra validation functionality. Put this file in your models directory and read the instruction in the comment
/**
* Really simple model-validation
* by extending a model with
* extra validation functionality
*
* Here's how it works
* /your-app/models/person.js:
* import DS from 'ember-data';
* import Validation from 'your-app/models/validation';
*
* export default Validation.extend({
* firstName : DS.attr('string'), // required
* lastName : DS.attr('string'), // required
* age : DS.attr('integer'), // numeric
* town : DS.attr('string'), // optional
* married : DS.attr('boolean',
{defaultValue: false}), // boolean
* email : DS.attr('string'), // e-mail
*
* requiredFields : ['firstName', 'lastName', 'age'],
* numericFields : ['age'],
* booleanFields : ['married'],
* emailFields : ['email']
* });
*
* Elsewhere in your code:
* var x = this.store.createRecord('person');
* x.firstName = 'Austin'; // is OK
* x.lastName = 'Powers'; // is OK
* x.town = 'London'; // is OK
* x.age = 'thirty'; // fails
* x.married = 'not really'; // fails
* x.email = 'fax only'; // fails
* var ok = x.is_valid();
* if( ok ) {
* console.log('OK');
* }else{
* console.log('ERROR');
* console.log('All error-messages:', x.get('errors').get('messages'));
* }
*
* or validate fields specificly:
* if( !this.get('model').is_valid_field( 'firstName' ) ) {
* console.log('firstName' + ' has error:');
* this.get('model').get('errors').errorsFor( 'firstName' ).forEach(function(err){
* console.log(err.message);
* });
* }else{
* console.log('firstName' + ' is all good');
* }
*
*
* Those model-errors are very useful in your templates
* where you could either use all error-messages:
* model.errors.messages
* or field-specific error-messages:
* model.errors.age.errors (=array where each error-item has a message)
* More info regarding model-errors at: http://emberjs.com/api/data/classes/DS.Errors.html
*
* Setting the error messages can be done in two ways;
* Override the default-messages directly on the model:
* export default Validation.extend({
* MESSAGE_REQUIRED : "Just anything..",
* MESSAGE_NUMERIC : "All I want is a frickin' number",
* MESSAGE_BOOLEAN : "Don't you bool me!",
* MESSAGE_EMAIL: "Valid email, please..."
*
* firstName : "", // required
* lastName : "", // required
* age : 0, // numeric
* town : "", // optional
* married : false, // boolean
* email : "", // e-mail
*
* requiredFields : ['firstName', 'lastName', 'age'],
* numericFields : ['age'],
* booleanFields : ['married'],
* emailFields : ['email']
* });
*
* or pass your messages when calling the validation methods:
* x.is_valid({
* message_required: "Just anything..",
* message_numeric: "All I want is a frickin' number",
* message_boolean: "Don't you bool me!",
* message_email: "Valid email, please..."
* });
* x.is_valid_field('firstName', {
* message_required: "Just anything..",
* message_numeric: "All I want is a frickin' number",
* message_boolean: "Don't you bool me!",
* message_email: "Valid email, please..."
* });
*
*
* @author sejKo
* @version 0.2.1
*
*/
import DS from 'ember-data';
export default DS.Model.extend({
/**
* Override this field by populating an array
* with names of fields which are required
*/
requiredFields : [],
/**
* Override this field by populating an array
* with names of fields which must be numeric
*/
numericFields : [],
/**
* Override this field by populating an array
* with names of fields which must be booleans
*/
booleanFields : [],
/**
* Override this field by populating an array
* with names of fields which must be valid e-mail adresses
*/
emailFields : [],
/**
* Default messages
*/
MESSAGE_REQUIRED : 'This field is required',
MESSAGE_NUMERIC : 'This field must be numeric',
MESSAGE_BOOLEAN : 'This field must be True / False',
MESSAGE_EMAIL : 'This field must contain a valid e-mail address',
/**
* Public method to call to validate a model instance
*
* How to set field-messages :
* myModel.is_valid({
* message_required: "Just anything..",
* message_numeric: "All I want is a frickin' number",
* message_boolean: "Don't you bool me!",
* message_email: "Valid email, please..."
* });
*
* @param object optional
* @return boolean
*/
is_valid : function ( messages ) {
var msgs = messages || {};
var message_required = msgs.message_required || null;
var message_numeric = msgs.message_numeric || null;
var message_boolean = msgs.message_boolean || null;
var message_email = msgs.message_email || null;
this.get('errors').clear();
var ok = true;
if( !this._is_valid_required( message_required ) ){ ok = false; }
if( !this._is_valid_numeric( message_numeric ) ){ ok = false; }
if( !this._is_valid_boolean( message_boolean ) ){ ok = false; }
if( !this._is_valid_email( message_email ) ){ ok = false; }
return ok;
},
/**
* Public method to call to validate a model instance
*
* How to set field-messages :
* myModel.is_valid_field('firstName', {
* message_required: "Just anything..",
* message_numeric: "All I want is a frickin' number",
* message_boolean: "Don't you bool me!",
* message_email: "Valid email, please..."
* });
*
* @param string
* @param object optional
* @return boolean
*/
is_valid_field : function (field, messages) {
var msgs = messages || {};
var message_required = msgs.message_required || null;
var message_numeric = msgs.message_numeric || null;
var message_boolean = msgs.message_boolean || null;
var message_email = msgs.message_email || null;
if( this.get('errors').has( field ) ) {
this.get('errors').errorsFor( field ).clear();
}
var ok = true;
if( this.requiredFields.indexOf(field) >= 0 && !this._is_valid_required_field( field, message_required ) ){ ok = false; }
if( this.numericFields.indexOf(field) >= 0 && !this._is_valid_numeric_field( field, message_numeric ) ){ ok = false; }
if( this.booleanFields.indexOf(field) >= 0 && !this._is_valid_boolean_field( field, message_boolean ) ){ ok = false; }
if( this.emailFields.indexOf(field) >= 0 && !this._is_valid_email_field( field, message_email ) ){ ok = false; }
return ok;
},
/**
* Allows anything that isn't empty
* for the this.requiredFields list
*
* @param string optional
* @return boolean
*/
_is_valid_required : function ( message ) {
var msg = message || this.MESSAGE_REQUIRED;
var self = this;
var ok = true;
this.get('requiredFields').forEach( function(field /*, index*/){
if( !self._is_valid_required_field(field, msg) ) {
ok = false;
}
});
return ok;
},
/**
* Allows anything that isn't empty
*
* @param string
* @param string optional
* @return boolean
*/
_is_valid_required_field : function (field, message) {
var msg = message || this.MESSAGE_REQUIRED;
var check = typeof check === 'string' ? this.get( field ).trim() : this.get( field );
if( check === '' ){
this.get('errors').add(field, msg);
return false;
}
return true;
},
/**
* Allows numbers as strings and numbers
* for the this.numericFields list
*
* @param string optional
* @return boolean
*/
_is_valid_numeric : function ( message ) {
var msg = message || this.MESSAGE_NUMERIC;
var self = this;
var ok = true;
this.get('numericFields').forEach( function(field /*, index*/){
if( !self._is_valid_numeric_field(field, msg) ) {
ok = false;
}
});
return ok;
},
/**
* Allows numbers as strings and numbers
*
* @param string
* @param string optional
* @return boolean
*/
_is_valid_numeric_field : function (field, message) {
var msg = message || this.MESSAGE_NUMERIC;
var check = typeof check === 'string' ? this.get( field ).trim() : this.get( field );
if( isNaN(parseFloat(check)) || !isFinite(check) ){
this.get('errors').add(field, msg);
return false;
}
return true;
},
/**
* Allows booleans only
* for the this.booleanFields list
*
* @param string optional
* @return boolean
*/
_is_valid_boolean : function ( message ) {
var msg = message || this.MESSAGE_BOOLEAN;
var self = this;
var ok = true;
this.get('booleanFields').forEach( function(field /*, index*/){
if( !self._is_valid_boolean_field(field, msg) ) {
ok = false;
}
});
return ok;
},
/**
* Allows booleans only
*
* @param string
* @param string optional
* @return boolean
*/
_is_valid_boolean_field : function (field, message) {
var msg = message || this.MESSAGE_BOOLEAN;
var check = this.get( field );
if( typeof check !== 'boolean' || (typeof check === 'object' && typeof check.valueOf() === 'boolean') ){
this.get('errors').add(field, msg);
return false;
}
return true;
},
/**
* Allows valid e-mail adresses only
* for the this.emailFields list
*
* @param string optional
* @return boolean
*/
_is_valid_email : function ( message ) {
var msg = message || this.MESSAGE_EMAIL;
var self = this;
var ok = true;
this.get('emailFields').forEach( function(field /*, index*/){
if( !self._is_valid_email_field(field, msg) ) {
ok = false;
}
});
return ok;
},
/**
* Allows valid e-mail adresses only
*
* @param string
* @param string optional
* @return boolean
*/
_is_valid_email_field : function (field, message) {
var msg = message || this.MESSAGE_EMAIL;
var check = this.get( field );
var re = /[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}/igm;
if( check !== '' && !re.test( check ) ){
this.get('errors').add(field, msg);
return false;
}
return true;
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment