A form input builder and validator for Angular JS
JavaScript
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
releases/0.1.0
src
.gitignore
Gulpfile.js
LICENSE
README.md
bower.json
package.json

README.md

formsy-angular

A form input builder and validator for Angular JS

Background

I wrote an article on forms and validation with React JS, Nailing that validation with React JS, the result of that was an extension to React JS that I reimplemented in Angular JS.

The main concept is that forms, inputs and validation is done very differently across developers and projects. This extension to Angular JS aims to be that "sweet spot" between flexibility and reusability. Though Angular already has pretty good validation handling for forms it does not handle server requests and responses. It is also scoped to normal input elements. A formsy-input is just a value with validation linked to a form. How you choose to change that value does not matter, you can build anything you want.

What you can do

  1. Build any kind of form input directive. Not just traditional inputs, but anything you want and get that validation for free

  2. Add validation rules and use them with simple syntax

  3. Use handlers for different states of your form. Ex. "submit", "error", "submitted" etc.

  4. Server validation errors automatically binds to the correct form input

Install

  1. Download from this REPO and use globally or with requirejs
  2. Install with npm install formsy-angular and use with browserify etc.
  3. Install with bower install formsy-angular

It registers as the module 'formsy':

  angular.module('MyApp', ['formsy']);

How to use

Formsy gives you a form straight out of the box

<formsy-form url="/users">
  <my-own-input name="email" validations="isEmail" validation-error="This is not an email" required/>
</formsy-form>

This code results in a form with a submit button that will POST to /users when clicked. The submit button is disabled as long as the input is empty (required) or the value is not an email (isEmail). On validation error it will show the message: "This is not a valid email".

This is an example of what you can enjoy building

angular.module('MyApp', ['formsy'])
  .directive('MyOwnInput', function () {

    return {
      restrict: 'E', // You need this one
      replace: true, // And this one
      scope: {}, // Aaand this one
      templateUrl: 'MyOwnInput.html'
    }

  });

The template:

<div formsy-input ng-class="{error: $showError, required: $showRequired}">
  <input type="text" ng-model="$value"/>
  <span>{{$message}}</span>
</div>

Be as creative as you want and still get validation for free

angular.module('MyApp', ['formsy'])
  .directive('MyIncreaser', function () {

    return {
      restrict: 'E',
      replace: true,
      scope: {},
      templateUrl: 'MyIncreaser.html',
      controller: function ($scope) {
        $scope.increase = function () {
          $scope.$value++;
        };
      }
    }

  });

The template:

<button formsy-input ng-class="{error: $showError, required: $showRequired}" ng-click="increase()">Increase ({{$value}})</button>

Use it in a form:

<formsy-form>
  <my-increaser name="increaser" validations="equals:3" validation-error="The value has to be 3" required/>
</formsy-form>

So this is basically how you build your form elements. As you can see it is very flexible, you just have a few scope properties to help you reflect the states. As long as you update the value on the scope everything will validate automatically.

API

formsyProvider.defaults(options)

angular.module('MyApp', ['formsy'])
  .config(function (formsyProvider) {
    formsyProvider.defaults({
      contentType: 'urlencoded', // default: 'json'
      hideSubmit: true, // default: false
      submitButtonClass: 'btn btn-success', // default: null
      cancelButtonClass: 'btn btn-default', // default: null
      buttonWrapperClass: 'my-wrapper' // default: null
    })
  });

Use defaults to set general settings for all your forms.

formsy-form

url

<formsy-form url="/users"></formsy-form>

Will either POST or PUT to the url specified when submitted.

method

<formsy-form url="/users" method="PUT"></formsy-form>

Supports POST (default) and PUT.

content-type

<formsy-form url="/users" method="PUT" content-type="urlencoded"></formsy-form>

Supports json (default) and urlencoded (x-www-form-urlencoded).

Note! Response has to be json.

hide-submit

<formsy-form url="/users" method="PUT" hide-submit></formsy-form>

Hides the submit button. Submit is done by ENTER on an input.

submit-button-class

<formsy-form url="/users" method="PUT" submit-button-class="btn btn-success"></formsy-form>

Sets a class name on the submit button.

cancel-button-class

<formsy-form url="/users" method="PUT" cancel-button-class="btn btn-default"></formsy-form>

Sets a class name on the cancel button.

button-wrapper-class

<formsy-form url="/users" method="PUT" button-wrapper-class="my-wrapper"></formsy-form>

Sets a class name on the container that wraps the submit and cancel buttons.

success(serverResponse)

<formsy-form url="/users" success="changeUrl()"></formsy-form>

Takes a function to run when the server has responded with a success http status code.

submit()

<formsy-form url="/users" submit="showFormLoader()"></formsy-form>

Takes a function to run when the submit button has been clicked.

submitted()

<formsy-form url="/users" submitted="hideFormLoader()"></formsy-form>

Takes a function to run when either a success or error response is received from the server.

error(serverResponse)

<formsy-form url="/users" error="changeToFormErrorClass()"></formsy-form>

Takes a function to run when the server responds with an error http status code.

formsy-input

So "formsy-input" is an attribute you use when creating your formsy directive to attach it to the form. It has to be set on the "top node" of the template. The first part of this section shows what attributes you can pass to your directive and the second part shows how you build the directive.

name

<my-input name="email"/>

The name is required to register the form input directive in the form.

validations

<my-input name="email" validations="isEmail"/>
<my-input name="number" validations="isNumeric,isLength:5:12"/>

An comma seperated list with validation rules. Take a look at Validators to see default rules. Use ":" to separate arguments passed to the validator. The arguments will go through a JSON.parse converting them into correct JavaScript types. Meaning:

<my-input name="fruit" validations="isIn:['apple', 'orange']"/>
<my-input name="car" validations="mapsTo:{'bmw': true, 'vw': true}"/>

Works just fine.

validation-error

<my-input name="email" validations="isEmail" validation-error="This is not an email"/>

The message that will show when the form input directive is invalid.

required

<my-input name="email" validations="isEmail" validationError="This is not an email" required/>

A property that tells the form that the form input directive value is required.

value

<my-input name="email" validations="isEmail" validationError="This is not an email" value="test@test.com" required/>

$value

To set a value inside your directive you can use two way data binding:

<input type="text" ng-model="$value"/>

Or set the value manually:

angular.module('MyApp', ['formsy'])
  .directive('MyInput', function () {
    return {
      restrict: 'E',
      replace: true,
      scope: {},
      controller: function ($scope) {
        $scope.setValue = function () {
          $scope.$value = $scope.$value === 'red' ? 'blue' : 'red';
        }
      }
    };
  });
<button type="text" ng-click="setValue()">Flip color</button>

$message

In your directive template:

<div>
  <input type="text" ng-model="$value"/>
  <div>{{$message}}</div>
</div>

Will display the server error mapped to the form input directive or return the validation message set if the form input directive is invalid. If no server error and the form input directive is valid it does not display anything.

$valid

In your directive template:

<div>
  <input type="text" ng-model="$value"/>
  <span>{{$valid ? ':-)' : ':-('}}</span>
</div>

Returns the valid state of the form input component.

$required

angular.module('MyApp', ['formsy'])
  .directive('MyInput', function () {
    return {
      restrict: 'E',
      replace: true,
      scope: {
        'label' '@' // Grab the label from the attributes
      }
    };
  });
<div>
  <label>{{label}} {{$required ? '*' : ''}}</label>
  <input type="text" ng-model="$value"/><span>
</div>

Returns true if the required attribute has been passed.

$showRequired

In your directive template:

<div ng-class="{required: $showRequired">
  <input type="text" ng-model="$value"/><span>
</div>

Lets you check if the form input directive should indicate if it is a required field. This happens when the form input directive value is empty and the required attribute has been passed, but its false if there is a validation error.

$showError

In your directive template:

<div ng-class="{required: $showRequired, error: $showError">
  <input type="text" ng-model="$value"/><span>
</div>

Lets you check if the form input directive should indicate if there is an error. This happens if there is a form input directive value and it is invalid or if a server error is received.

formsyProvider.addValidationRule(name, ruleFunc)

An example:

angular.module('MyApp', ['formsy'])
  .config(function (formsyProvider) {
    formsyProvider.addValidationRule('isFruit', function (value) {
      return ['apple', 'orange', 'pear'].indexOf(value) >= 0;
    });
  });
<my-input name="fruit" validations="'isFruit"/>

Another example:

angular.module('MyApp', ['formsy'])
  .config(function (formsyProvider) {
    formsyProvider.addValidationRule('isIn', function (value, array) {
      return array.indexOf(value) >= 0;
    });
  });
<my-input name="fruit" validations="isIn:['apple', 'orange', 'pear']"/>

Validators

isValue

<my-input name="foo" validations="isValue"/>

Returns true if the value is thruthful

isEmail

<my-input name="foo" validations="isEmail"/>

Return true if it is an email

isTrue

<my-input name="foo" validations="isTrue"/>

Returns true if the value is the boolean true

isNumeric

<my-input name="foo" validations="isNumeric"/>

Returns true if string only contains numbers

isAlpha

<my-input name="foo" validations="isAlpha"/>

Returns true if string is only letters

isLength:min, isLength:min:max

<my-input name="foo" validations="isLength:8"/>
<my-input name="foo" validations="isLength:5:12"/>

Returns true if the value length is the equal or more than minimum and equal or less than maximum, if maximum is passed

equals:value

<my-input name="foo" validations="equals:4"/>

Return true if the value from input component matches value passed (==).