Skip to content

britco/stonewall

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Stonewall

An asynchronous validation framework with tight integration to Backbone and Rivets.

Introduction

Stonewall is a simple Javascript validation framework. The goal of the framework is to provide a validation library that doesn't get in your way. But at the same time, Stonewall provides features that many validation frameworks are missing. For instance, Stonewall includes asynchronous validation by default, no plugins required. This means you can have validation rules like 'check if username is registered already', without having to do hacky things like passing async: false to $.ajax. Stonewall is in its infancy, so there may be bugs, but everything is thoroughly tested, and the framework is already being used in production on a number of sites.

Download

Stonewall-0.1.1.js

Dependencies

Docs

License

Available under the MIT License.

Basic Setup

This information should help you get up and going with Stonewall. First download the source code, and include in your page.

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="lib/underscore.js"></script>
<script type="text/javascript" src="lib/Stonewall-0.1.1.js"></script>

Setting up rules

Rulesets are easy to create. Simply create an object with the properties as the attribute names, and the values as the rules / options. For example:

rules = {
	'username': {
		'required': true,
		'maxLength': 5
	}
}

There is also the array syntax. Use this if you want to specify a custom error message for a rule, like so:

rules = [
	username: [
		{
			minLength: 4
			msg: 'username is not long enough.'
		}
	]
]

Validating the rules

After you have the rules, you can validate data against the rules by calling Stonewall.validate. Pass in the attributes & rules, and also callbacks for when the validation is complete.

data = {
	'first_name': '',
	'last_name': '2',
	'street_line1': '1',
	'zipcode': 1311114
};

rules = {
	'street_line1': {
		'required': true,
		'maxLength': 5,
	}
	'zipcode': {
		'required': true,
		'length': 5,
		'pattern': 'number'
	}
};

Stonewall.validate(
{
	attributes: data,
	rules: rules,
	success: function() {
		console.log('Success! No errors.');
	},
	error: function(errs) {
		console.log('Validation failed, errors:', errs);
	}
});

Validated nested properties

Validated nested properties is trivial with Stonewall. Say you have an object like:

obj = {
	billing_info': {
		cvc: 13
	}
}

When this data is validated, it will be flattened to the following:

obj = {
	'billing_info.cvc' : 13
}

That makes it super easy to set up validation on the cvc property.

rules = {
	'billing_info.cvc': {
		required: true
	}
}

Setup with Backbone & Rivets

Stonewall works really well with a Rivets & Backbone setup. If you want to use Stonewall in this setup, first set up some rules on a Backbone model's validation property:

UserModel = Backbone.Model.extend({
	validation: {
		email: [
			{
				required: true,
				msg: 'required'
			},
			{
				pattern: 'email',
				msg: 'invalid format'
			}
		],
		username: [
			{
				required: true
				msg: 'required'
			},
			{
				minLength: 4
				msg: 'must be at least 4 characters'
			},
			{
				pattern: /^[.\w-]+$/
				msg: 'invalid format'
			}
		]
	}
})

Then, set up the Rivets binding like you normally would.

Backbone View:

...
@rivets = rivets.bind $(@container), { user: @model }
...

Template:

...
<input type="text" name="first_name" data-value="user.first_name">
...

That's all you have to do. Stonewall will modify the Rivets value binding to validate the property on change, and if it passes, proceed to set the value.

And also, full validation will occur when a form is submitted. This means, if you have the following:

<form id="register">
	<input id="username" type="text" name="username" data-value="user.username">
	<input id="email" type="text" name="email" data-value="user.email">
</form>

When #register is submitted, Stonewall.validate will be called for #username and #email.

Another cool feature of this integration, is that anytime, if you wanted to check the state of the Rivets view you previously set up (@rivets), you can call @rivets.isValid() and it will return either true or false.

Configuration

You can change some of the way the internals of Stonewall work by using Stonewall.configure. Right now the only configurable options are for the Stonewall Rivets integration. You can configure the showError and hideError functions. These are callbacks for when an element becomes invalid / valid. So say you have an input like:

And you also have validation rules like:

rules = {
	'required' : true
}

When email becomes invalid, showError is called.

$("#email").showError({ 'message': 'Email is required' })

If you don't configure showError it will do the following:

$(@).addClass('error')
    .removeClass('valid')
    .attr('data-error', options.message || '')
    .nextAll('.msg:not(.valid)').each ->
		$(@).text(options.message)
		$(@).fadeIn()

The default functions will get you a far way, but if you need to, they can be configured like so:

Stonewall.configure('plugin', 'rivets',
	showError: (options) ->
		# Options looks like options = { message: 'Email is invalid!' }
	hideError: ->
		# Do something here
)

Built in rules

required

Specifies if a value is required or not.

rules = {
	'first_name': {
		'required': true
	}
}

minLength

Value must meet the mininum length to pass.

rules = {
	'name': {
		'minLength': 3
	}
}

maxLength

Value cannot exceed this length.

rules = {
	'name': {
		'maxLength': 10
	}
}

rangeLength

Value must be in between this length.

rules = {
	'username': {
		rangeLength: [6, 20]
	}
}

length

Must be exactly this length.

rules = {
	'address': {
		length: 12
	}
}

equalTo

Value must equal this other value.

rules = {
	'password_confirm': {
		equalTo: 'password'
	}
}

pattern

Value must match this pattern. You can use a built in pattern, your specify your own.

rules = {
	'username': {
		pattern: /^[.\w-]+$/
	}
}

The built in patterns are:

  • number: /^([0-9]+)$/
  • email: /^(.+)@(.+){2,}\.(.+){2,}$/

fn

Use this rule to validate data against a custom function. The function accepts the arguments (value, field). If you return true from the function, the rule passes, otherwise it doesn't.

Alternatively, you can return a deffered object. If the function returns a deffered object, the return status of the deffered object will be used as the passing status of the data. So for the below example, if 'user/exists' throws a 200, the rule will pass, but if it throws a 500, it will fail.

resource = {
	'validateUnique': function(value, field) {
		return $.ajax({
			type: 'POST',
			url: 'user/exists',
			data: value,
			dataType: 'json',
			contentType: 'application/json'
		});
	}
};

rules = {
	'username': {
		fn: 'validateUnique'
	}
};

data = {
	'username': 'test'
};

Stonewall.validate({
	resource: resource,
	attributes: data,
	rules: rules,
	success: function() {
		console.log('Success! No errors.');
	},
	error: function(e) {
		console.log('Validation failed, errors:', e);
	}
});