Code Monkey home page Code Monkey logo

valdr's Introduction

A model centric approach to AngularJS form validation

Why valdr

Defining the validation rules on every input field with the default AngularJS validators pollutes the markup with your business rules and makes them pretty hard to maintain. This is especially true for larger applications, where you may have recurring models like persons or addresses in different forms, but require slightly different markup and therefore can't just reuse an existing form via ng-include or a form directive. What's even worse: Usually you already have the validation logic in your back-end, but there is no easy way to share this information with the UI.

valdr solves these issues by extracting the validation constraints from the markup to a JSON structure. You define the constraints per type and field, tell valdr that a form (or just a part of the form) belongs to a certain type and valdr automatically validates the form fields.

valdr gives you the following advantages:

  • cleaner form markup
  • reusable validation constraints for your models -> easier to maintain
  • possibility to generate the constraints from the models you already have in your back-end (see valdr-bean-validation for Java)
  • an easy way to display validation messages per form field
  • seamless integration with angular-translate for i18n of the validation messages

Install

bower install --save valdr

Getting started

  1. Add valdr.js to your index.html

  2. Add it as a dependency to your apps module:

angular.module('yourApp', ['valdr']);
  1. Define the constraints:
yourApp.config(function(valdrProvider) {
  valdrProvider.addConstraints({
    'Person': {
      'lastName': {
        'size': {
          'min': 2,
          'max': 10,
          'message': 'Last name must be between 2 and 10 characters.'
        },
        'required': {
          'message': 'Last name is required.'
        }
      },
      'firstName': {
        'size': {
          'min': 2,
          'max': 20,
          'message': 'First name must be between 2 and 20 characters.'
        }
      }
    }
});
  1. Add the valdr-type directive in your form on any parent element of the input fields that you want to validate. The important thing is, that the attribute name on the input field matches the field name in the constraints JSON.
<form name="yourForm" novalidate valdr-type="Person">
    <label for="lastName">Last Name</label>
    <input type="text"
           id="lastName"
           name="lastName"
           ng-model="person.lastName">

    <label for="firstName">First Name</label>
    <input type="text"
           id="firstName"
           name="firstName"
           ng-model="person.firstName">
</form>

That's it. valdr will now automatically validate the fields with the defined constraints and set the $validity of these form items. All violated constraints will be added to the valdrViolations array on those form items.

Constraints JSON

The JSON object to define the validation rules has the following structure:

  TypeName {
    FieldName {
      ValidatorName {
        <ValidatorArguments>
        message: 'error message'
      }
    }
  }
  • TypeName The type of object (string)
  • FieldName The name of the field to validate (string)
  • ValidatorName The name of the validator (string) see below in the Built-In Validators section for the default validators
  • ValidatorArguments arguments which are passed to the validator, see below for the optional and required arguments for the built-in validators
  • Message the message which should be shown if the validation fails (can also be a message key if angular-translate is used)

Example:

  "Person": {
    "firstName": {
      "size": {
        "min": 2,
        "max": 20,
        "message": "First name must be between 2 and 20 characters."
      }
    }
  },
  "Address": {
    "email": {
      "email": {
        "message": "Must be a valid E-Mail address."
      }
    },
    "zipCode": {
      "size": {
        "min": "4",
        "max": "6",
        "message": "Zip code must be between 4 and 6 characters."
      }
    }
  }

Built-In Validators

size

Checks the minimal and maximal length of the value.

Arguments:

  • min The minimal string length (number, optional, default 0)
  • max The maximal string length (number, optional)

minLength / maxLength

Checks that the value is a string and not shorter / longer than the specified number of characters.

Arguments:

  • number The minimal / maximal string length (number, required)

min / max

Checks that the value is a number above/below or equal to the specified number.

Arguments:

  • value The minimal / maximal value of the number (number, required)

required

Marks the field as required.

pattern

Validates the input using the specified regular expression.

Arguments:

  • value The regular expression (string/RegExp, required)

email

Checks that the field contains a valid e-mail address. It uses the same regular expression as AngularJS is using for e-mail validation.

digits

Checks that the value is a number with the specified number of integral/fractional digits.

Arguments:

  • integer The integral part of the number (number, required)
  • fraction The fractional part of the number (number, required)

url

Checks that the value is a valid URL. It uses the same regular expression as AngularJS for the URL validation.

future / past

Check that the value is a date in the future/past. NOTE These validators require that Moment.js is loaded.

Adding custom validators

Implementing custom validation logic is easy, all you have to do is implement a validation service/factory and register it in the valdrProvider.

  1. Custom validator:
yourApp.factory('customValidator', function () {
  return {
    name: 'customValidator', // this is the validator name that can be referenced from the constraints JSON
    validate: function (value, arguments) {
      // value: the value to validate
      // arguments: the validator arguments
      return value === arguments.onlyValidValue;
    }
  };
});
  1. Register it:
yourApp.config(function (valdrProvider) {
  valdrProvider.addValidator('customValidator');
}
  1. Use it in constraints JSON:
yourApp.config(function (valdrProvider) {
  valdrProvider.addConstraints({
    'Person': {
      'firstName': {
        'customValidator': {
          'onlyValidValue': 'Tom',
          'message': 'First name has to be Tom!'
        }
      }
    }
  });
}

Showing validation messages with valdr-messages

valdr sets the AngularJS validation states like $valid, $invalid and $error on all validated form elements and forms by default. Additional information like the violated constraints and the messages configured in the constraints JSON are always set as valdrViolations array on the individual form items. With this information, you can either write your own logic to display the validation messages, or use valdr-messages to automatically show the messages next to the invalid form items.

To enable this behaviour, include valdr-message.js in your page (which is included in the bower package) and make use of the valdr-form-group directive. This directive marks the element, where the valdr messages will be appended. The valdr-form-group can wrap multiple valdr validated form items. Each form item has to have at least one surrounding valdr-form-group to automatically show validation messages.

Message template

The default message template to be used by valdr-messages can be overridden by configuring the valdrMessageProvider:

valdrMessageProvider.setTemplate('<div class="valdr-message">{{ violation.message }}</div>');

// or

valdrMessageProvider.setTemplateUrl('/partials/valdrMesssageTemplate.html');

The following variables will be available on the scope of the message template:

  • violations - an array of all violations for the current form field
  • violation - the first violation, if multiple constraints are violated it will be the one that is first declared in the JSON structure
  • formField - the invalid form field

CSS to control visibility

valdr sets some CSS classes on elements with the valdr-form-group directive and on the message elements which are automatically added by valdr-messages. These classes allow you to control the visibility of the validation messages.

To change the CSS class names used by valdr, you can inject valdrClassesand override the following values:

{
  // added on all elements with valdr-form-group directive
  formGroup: 'form-group',
  // added on valdr-form-group and on valdr-messages if all of the form items are valid
  valid: 'ng-valid',
  // added on valdr-form-group and on valdr-messages if one of the form items is invalid
  invalid: 'ng-invalid',
  // added on valdr-messages if the form item this message is associated with is dirty
  dirty: 'ng-dirty',
  // added on valdr-messages if the form item this message is associated with is pristine
  pristine: 'ng-pristine',
  // added on valdr-messages if the form item this message is associated with has been blurred
  touched: 'ng-touched',
  // added on valdr-messages if the form item this message is associated with has not been blurred
  untouched: 'ng-untouched',
  // added on valdr-form-group if one of the contained items is currently invalid, dirty and has been blurred
  invalidDirtyTouchedGroup: 'valdr-invalid-dirty-touched-group'
}

Using CSS like the following, the messages can be shown only on inputs which the user changed, blurred and are invalid:

.valdr-message {
  display: none;
}
.valdr-message.ng-invalid.ng-touched.ng-dirty {
  display: inline;
  background: red;
}

Integration of angular-translate

To support i18n of the validation messages, valdr has built-in support for angular-translate.

Instead of adding the message directly to the constraints, use a message key and add the translations to the $translateProvider. In the translations, the constraint arguments and the field name can be used with placeholders as in the following example:

valdrProvider.addConstraints({
  'Person': {
    'lastName': {
      'size': {
        'min': 5,
        'max': 20,
        'message': 'message.size'
      }
    }
  }
});

$translateProvider.translations('en', {
  'message.size': '{{fieldName}} must be between {{min}} and {{max}} characters.',
  'Person.lastName': 'Last name'
});

$translateProvider.translations('de', {
  'message.size': 'Zwischen {{min}} und {{max}} Zeichen sind im Feld {{fieldName}} erlaubt.',
  'Person.lastName': 'Nachname'
});

Conditionally enable/disable validation

The valdrEnabled directive allows to dynamically enable and disable the validation with valdr. All form elements in a child node of an element with the 'valdr-enabled' directive will be affected by this.

Usage:

<div valdr-enabled="isValidationEnabled()">
  <input type="text" name="name" ng-model="mymodel.field">
</div>

If multiple valdr-enabled directives are nested, the one nearest to the validated form element will take precedence.

Wire up your back-end

To load the validation constraints from your back-end, you can configure the valdrProvider in a config function like this:

yourApp.config(function(valdrProvider) {
  valdrProvider.setConstraintUrl('/api/constraints');
});

Using JSR303 Bean Validation with Java back-ends

If you have a Java back-end and use Bean Validation (JSR 303) annotations, check out the valdr-bean-validation project. It parses Java model classes for Bean Validation constraints and extracts their information into a JSON document to be used by valdr. This allows to apply the exact same validation rules on the server and on the AngularJS client.

Develop

Clone and install dependencies:

git clone https://github.com/netceteragroup/valdr.git
cd valdr
npm install

Start live-reload

grunt dev

Then start the dev server

grunt server

Open http://localhost:3005/demo in your browser.

Support

Open a question on SO and tag it with valdr.

License

MIT © Netcetera AG

Credits

Kudos to the gang who brainstormed the name for this project over a dinner on mount Rigi with us. Guys, we really appreciate your patience!

valdr's People

Contributors

philippd avatar marcelstoer avatar b8li avatar gitter-badger avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.