Angular Form Validations

Ibrahim Muhammad

Twitter: @ibrahimm

http://ibrahimmuhammad.com

https://slides.com/ibrahimm/ng-validation

<input type="number"
       ng-model="creditCard.number"
       name="number"
       min="0" max="9999999999999999"
       integer />
<span ng-show="form.size.$error.integer">
    The value is not a valid integer!
</span>
<span ng-show="form.size.$error.min || form.size.$error.max">
    The value must be in range 0 to 9999999999999999!
</span>
  • Validation goes in the views
  • Works well in a number of places

The Angular Way

The good and the bad

The Good:

  • Easy -¬†angular directives to help
  • Customizable view to view

The Bad:

  • Can easily be not DRY
  • Custom validations are hard to generalize in directives

Error Object

{
    "expiryDate": ["Expiry date must be after today"],
    "number": false // or missing
}

Moving to a Service

function validate(){
    var errors = {};
    if (this.expiryDate > today) {
        addError(errors, 'name', 'Expiry date must be after today');
    }
    return errors;
}
  • DRYer, if used in multiple views
  • We lose the angular provided helpers

Validation helpers

function validateDateGreaterThan(model, attribute, value) {
    if (model[attribute]) <= value) {
        addError(model, attribute, attribute + ' must be after '+ value);
        // error added to model.errors
    }
}

validateDateGreaterThan(creditCard, 'expiryDate', Date.now())

More Delarative

var schema = {
    'expiryDate': {
        'min': new Date("1 Jan 1980"),
        'max': Date.now(),
        'type': 'date'
    }
}
var errors = validate(model, schema);
  • possibly use JSON schema with existing validators

Custom Validations (1)

var schema = {
    'number': {
        'min': function(creditcard) {
            var len = creditcard.number.length;
            if (creditcard.type === 'visa'){
                return (len === 13 || len == 16);
            } else { //mastercard
                return len === 16;
            }
        }
    }
}
  • Use functions or values (inspiration from grunt)

Custom Validations (2)

var schema = {
    'number': {
        'checksum': function(creditcard) {
            var errorMessage = "Checksum is not valid";
            return [isChecksumValid(creditcard.number), errorMessage];
        }
    }
}

More Human

validate(creditcard)
    .field('number').type('number')min(0).max(9999999999999999).checksum()
    .field('expiryDate').type('date').min(Date(MIN_DATE)).max(Date.Today())
  • Use method chaining

Thanks!

Interested in OS library that does this? @ibrahimm