Plaits is a form creation, validation and rendering library for Node.js.
It supports both synchronous and asynchronous validation (via Promises), and comes with many built-in validators, many of which are provided by the excellent validator.js library.
It is intended for use with Express, but can be used with other libraries and frameworks too.
Plaits is inspired by the form validation features found in frameworks such as .NET MVC, and thanks goes to the great work done on the Bookshelf ORM for additional inspiration and helping with some underlying code principles.
The source is available on GitHub, and it comes with a large suite of unit tests.
Version 0.1.10.
View the Changelog below.
Please feel free to report bugs and suggest features you’d like to see on the Plaits GitHub Issues Page, or send tweets to @persata.
Plaits models are simply Backbone models with different functionality.
A model must be given a name, and a list of fields. It also takes an optional list of validators (examples later).
A basic model example:
// Require Plaits
var Plaits = require('plaits');
// Register Form Declaration
var RegisterForm = Plaits.Model.extend(
{
// Form Name
name: 'register_form',
// Field List
fields: [
'username',
'email_address',
'password',
'confirm_password'
],
// Validators
validators: {
username: [
Plaits.Validators.required(),
Plaits.Validators.alphanumeric()
],
email_address: [
Plaits.Validators.required(),
Plaits.Validators.email()
],
password: [
Plaits.Validators.required(),
Plaits.Validators.minLength(8)
],
confirm_password [
Plaits.Validators.matchProperty('password')
]
}
}
);
// Export Form
module.exports = RegisterForm;
Models can also take a labels object as part of their declaration:
// Register Form Declaration
var RegisterForm = Plaits.Model.extend(
{
...
labels: {
'username': 'Your Chosen Username'
}
...
}
);
If a label is not provided, it will be auto generated by Node Inflection’s titleize function, for example:
email_address => 'Email Address'
confirm_password => 'Confirm Password'
This will return either the custom label you have set in the model itself, or will generate one.
You can specify the defaults for model values using the defaults
key:
// Register Form Declaration
var RegisterForm = Plaits.Model.extend(
{
...
defaults: {
'email_address': 'email@example.com'
}
...
}
);
To instantiate a form model, simply require it (if necessary) & use new
:
// Require
var RegisterForm = require('../forms/register');
// New Register Form
var registerForm = new RegisterForm();
Gets the field identifier for a model’s field - this is used to generate a form name / ID that the parseRequest()
functions can automatically parse.
It is made up of the field’s name and the model’s name joined with an underscore - see Form Request Parsing.
// Get Field Identifier
model.getFieldIdentifier(field);
// Examples
console.log(registerForm.getFieldIdentifier('email_address'));
// => 'register_form_email_address'
console.log(registerForm.getFieldIdentifier('username'));
// => 'register_form_username'
Gets the label text for a model’s field. Used to fetch or generate the label text.
// Get Label for a Field
model.getLabelText(field);
// Examples
console.log(registerForm.getLabelText('email_address'));
// => 'Email Address'
console.log(registerForm.getLabelText('username'));
// => 'Username'
Checks the provided validators to see if the given field is required. This is achieved by analysing the function names for requiredValidator
.
// Get Required Status
model.isRequired(field);
// Examples
console.log(registerForm.isRequired('email_address'));
// => true
Adds the specified error message to the specified field. Use if you want to manually add an error message for a field to the form.
// Add an Error
model.addError(field, errorMessage);
// Example
registerForm.addError('username', 'Manually adding this error message.');
console.log(registerForm.getFirstError('username'));
// => 'Manually adding this error message.'
Check whether the specified field has any errors attached to it.
// Check For Errors
model.hasErrors(field);
// Example
console.log(registerForm.hasErrors('username'));
// => false
Check whether the specified field has a file uploaded to it - follows the same principles as file required validation, i.e. not undefined and size > 0.
// Check For File
model.hasFile(field);
// Example
console.log(registerForm.hasFile('avatar'));
// => true
Plaits comes with a large set of built in validators which should be able to handle many of your use cases. Many of the validators are backed by the validator.js library.
Many will take certain parameters to define their behaviour, for example minLength
will take a parameter to define
what the minimum length should be.
All built in validators take an optional custom error message if you wish to override the default error message.
You can use the string {{label}}
in your custom error messages to have the label for the field automatically inserted,
for example the string ‘{{label}} must be a minimum of 10 characters’ could produce ‘Your password must be a minimum of 10 characters’.
There are also other strings you can use depending on the validator, such as {{version}}
for IP Address, {{minLength}}
for minimum length etc. Each is described below.
Whether this field is required.
In most cases, this will check whether the value is null or not - null values are considered invalid.
When generating labels using the Html helpers and templates, the label text will be appended with an asterisk.
required([customErrorMessage])
Checks if the provided value is an email address.
email([customErrorMessage])
Checks that the value matches or exceeds the minimum length provided.
minLength(minLength, [customErrorMessage])
Checks that the value matches or is less than the maximum length provided.
maxLength(maxLength, [customErrorMessage])
This validator can be used to ensure an exact, minimum, or a range length of characters.
Ensure that if you are passing lengths that they are ints and not strings, so 6 instead of ‘6’.
It takes between 1 and 3 arguments, as follows:
1 Argument
2 Arguments
3 Arguments
length(args...)
Ensures the value provided is a numeric value.
numeric([customErrorMessage])
Ensures the value provided only contains letters.
alpha([customErrorMessage])
Ensures the value provided only contains letters and numbers.
alphanumeric([customErrorMessage])
This validator ensures that the value provided to the model is a valid URL.
It takes between 0 and 2 arguments, as follows:
0 Arguments:
1 Argument, either:
2 Arguments
url(args...)
{
protocols: ['http','https','ftp'],
require_tld: true,
require_protocol: false,
allow_underscores: false,
host_whitelist: false,
host_blacklist: false
}
This validator ensures that the value provided to the model is a valid IP address. It can be used to validate version 4 or version 6 addresses, or can be version agnostic.
It takes between 0 and 2 arguments, as follows:
0 Arguments:
1 Argument, either:
2 Arguments
ipAddress(args...)
Ensures the value provided is a valid credit card number.
creditCard([customErrorMessage])
When provided with an equalValue
parameter, this will make sure the value provided to the form equals the equalValue
provided.
equals(equalValue, [customErrorMessage])
This validator should be passed an array of acceptable values, and if the value provided to the form for validation is one of those, it will pass validation.
oneOf(allowedValues, [customErrorMessage])
This validator should be passed a string as the first parameter. If the value provided to the form for validation contains this value as a substring, it will pass validation.
contains(containsValue, [customErrorMessage])
This validator should be passed a regex as the first parameter. If the value provided to the form for validation matches this regex, it will pass validation.
matches(regexValue, [customErrorMessage])
This validator will loosely check that the provided value for validation is a date. It can be of any format, even a Unix timestamp.
date([customErrorMessage])
This validator will check that the value provided to the form for validation is a valid date, and is in the format specified.
It should be provided a date format string as an argument.
This validator is backended by the moment.js library.
When specifying a custom error message, you may use {{dateFormat}}
to have the specified format injected into your custom error message.
dateForm(dateFormat, [customErrorMessage])
This validator takes a property key as the first parameter.
When validation runs, it will check that the value provided to the form for validation is the same as the value of the given property.
This is usually used for comparing password & confirm password fields (see the example above).
matchProperty(propertyKey, [customErrorMessage])
This validator will check that the value provided to the form is an integer.
int([customErrorMessage])
This validator will check that the value provided to the form is floating point number.
float([customErrorMessage])
This validator will check that the value provided to the form is greater than or equal to the minimum value given.
min(min, [customErrorMessage])
This validator will check that the value provided to the form is less than or equal to the maximum value given.
max(max, [customErrorMessage])
This validator will check that the value provided to the form is between or equal to the minimum and maximum values given.
range(min, max, [customErrorMessage])
Plaits allows for the validation of file uploads, with some setup (see File Field Mapping)
Due to the various methods & libraries for handling file uploads in Node / Express, the resulting file fields on a file object differ depending on which library is being used.
For example, connect-multiparty will use originalFilename
and type
, whereas multer
will have equivalent fields of originalname
and mimetype
.
In order to allow the validation of file uploads to use one consistent API, Plaits allows for the mapping of file fields to allow the validators to look up which fields to use.
In the case of Multer:
// Use Multer
app.use(multer({dest: '/tmp/uploads/'}));
// Set Multer Mappings
Plaits.setValidatorConfig({fileFieldMappings: Plaits.FileFieldMappings.Multer});
and for Multiparty:
// Use Multiparty
app.use(multipart());
// Set Multiparty Config
Plaits.setValidatorConfig({fileFieldMappings: Plaits.FileFieldMappings.Multiparty});
For custom file field mapping (in the case you’ve written the form handler yourself / are using another library), you can specify the mappings to suit. For example:
// Mappings
var fileFieldMappings = {
originalFilename: 'original-file-name',
type: 'file-mime-type',
size: 'file-size'
};
// Set Mapping Config
Plaits.setValidatorConfig({fileFieldMappings: fileFieldMappings);
Whether this file field is required.
This will check if the uploaded file has a name and a size greater than 0 bytes.
When generating labels using the Html helpers and templates, the label text will be appended with an asterisk.
required([customErrorMessage])
This will check that the file being uploaded is greater than the minimum size provided to the function.
The minimum size value can given in either a numeric format, e.g. 60000 for bytes, or a string that follows JEDEC standards, e.g. 60kB
, 0.5mb
etc.
minSize(minSize, [customErrorMessage])
This will check that the file being uploaded is smaller than the maximum size provided to the function.
The maximum size value can given in either a numeric format, e.g. 60000 for bytes, or a string that follows JEDEC standards, e.g. 60kB
, 0.5mb
etc.
maxSize(maxSize, [customErrorMessage])
This will check that the file being uploaded is one of the MIME-Types provided to the function.
The function should be passed a string for a single MIME-Type, or an array of allowed MIME-Types.
The MIME-Type value given to the function can include wildcards if needed, for example ['image/*']
, ['audio/*']
, or can be an exact MIME-Type such as ['application/rtf']
.
mimeTypes(mimeTypes, [customErrorMessage])
Malicious users may attempt to upload files to your forms which are not what they seem - for example, uploading a file with extension ‘.jpg’ that is actually a ‘.zip’ file etc.
This validator uses mmmagic bindings to libmagic to inspect the uploaded file and ensure that the file’s MIME-Type actually matches its contents.
Due to the async nature of the libmagic bindings, this validator must be used with the validate()
method on the form, as validateSync()
will not suffice.
enforceMimeMatch([customErrorMessage])
Plaits provides the ability to define custom validation functions for your form models.
The returned result of the custom validation function will be cast to a promise, so the validation function can be synchronous or asynchronous depending on the requirements of the validation.
If the value provided is valid, then the overall function should return ‘true’, however if the value is invalid, a string should be returned explaining why the field is invalid.
Asynchronous use cases would be such things as checking a database to ensure a unique email address or username.
Custom validation functions should be defined as such:
/**
* Define Your Unique Email Validator
* @param fieldValue - The value of the field
* @param fieldLabel - The label of the field
* @param formModel - The current instance of the form model this validator belongs to
* @param additionalVars - Additional vars passed to the validate() function (explained later)
*/
var uniqueEmailValidator = function(fieldValue, fieldLabel, formModel, additionalVars) {
// Table
var userTable = knexInstance('users');
// Query
return userTable.select('email').where('email', '=', fieldValue).then(function(result) {
// Result Count
if (result.length > 0) {
// Return An Error
return 'That email address is already in use!';
} else {
// Return True (Valid)
return true;
}
});
};
// Add to Register Form Declaration
var RegisterForm = Plaits.Model.extend(
{
...
validators: {
email_address: uniqueEmailValidator
}
...
}
);
If you are using the Express framework, you can have the module parse requests made to your routes.
This will analyse your GET and POST parameters, and assign the values to the form as they are found.
Values should be passed as (form name)_(field name)
, for example register_form_email_address
, register_form_confirm_password
and so on.
// Register Form
var RegisterForm = require('../forms/register');
// Test Route - POST
// Synchronous Parsing (Most common)
router.post('/test', function(req, res) {
// New Form
var registerForm = new RegisterForm();
// Parse Request
registerForm.parseRequestSync(req);
});
// Test Route - POST
// Asynchronous Parsing. Useful if you are using any related events that are also asynchronous.
// Unlikely but doesn't hurt to provide the option.
router.post('/test', function(req, res) {
// New Form
var registerForm = new RegisterForm();
// Parse Request, Promise Based
registerForm.parseRequest(req).then(function(formModel) {
// ...
});
});
The main use of Plaits is to validate the data passed to the model and return feedback based on the validation result.
Validation can be done synchronously or asynchronously depending on the requirements of the form - if using all synchronous validators, then you can validate synchronously for simpler flow control. If there is a validator that needs to be asynchronous (such as checking a web service or querying a database), then you can validate asynchronously using Promises.
All current stock validators are synchronous, with the exception of the undocumented and yet unfinished File validators (see coming soon).
To validate a model asynchronously, use the validate()
method, which returns a Promise, eventually being fulfilled with the result of the validation.
Please note that the Promise is only rejected when something goes wrong with the validation - database connection timeout, exceptions etc. If the model is invalid (i.e. the end result is false), the promise is still fulfilled, with a false value. For a great explanation, see this cartoon.
// Validate
registerForm.validate().then(function (result) {
// ...
});
To validate a model asynchronously, use the validateSync()
method, which returns the result of the validation:
// Validate
var result = registerForm.validateSync();
It is often the case that if you’re using a custom validator, you want to pass extra objects or information into the validation function (current user account etc).
This is possible with the additionalVars
parameter on both the validate()
and validateSync()
methods, which will then pass the objects into the custom validation function:
// Current User
var currentUser = req.user;
// Validate With Additional Vars
var result = registerForm.validateSync(currentUser);
// Custom Validator Function
var differentPassword = function(fieldValue, fieldLabel, formModel, currentUser) {
// Do Things With 'currentUser'
};
Validation would be useless if it were not able to display useful feedback to the user. When a field fails validation, the error is added to the internal _errors
object.
You can get errors from the model with the following functions:
Returns the errors for all fields, or if passed a ‘field’ parameter, returns errors for only that field.
If there are no errors, returns an empty object.
model.getErrors([field])
Returns the first error for the specified field.
If there are no errors for that field, returns an empty string.
model.getFirstError(field)
The errors object is a key:array object that contains an entry for each field that has validation errors, for example:
{
'username': [
'Username must be at least 8 characters long.',
'Username must consist of only letters and numbers.'
],
'password': [
'Password is a required field.'
]
}
Plaits models come with custom events that allow you to hook in and modify model behaviour or attributes when triggered.
Since Plaits models are essentially glorified Backbone models, you have access to all the underlying event functionality that Backbone provides. See the Backbone documentation for each of:
Events use trigger-then, allowing for asynchronous behaviour in your event listeners if necessary.
Ensure however, that if you are using asynchronous events that you use the asynchronous versions of parseRequest
and validate
.
Specify the events using on()
in your initialize method like so:
// Register Form Declaration
var RegisterForm = Plaits.Model.extend(
{
...
initialize: function () {
this.on('beforeParseRequest', function (model, request) {
...
});
},
...
}
);
This even fires before a request is parsed, allowing you to modify the request or the model.
/**
* Before Parse Event
* @param model PlaitsModel - The form model
* @param request Object - The express request object
*/
this.on('beforeParseRequest', function (model, request) {
...
});
This even fires after a request is parsed.
/**
* Before Parse Event
* @param model PlaitsModel - The form model
* @param request Object - The express request object
*/
this.on('afterParseRequest', function (model, request) {
...
});
This even fires before a model is validated.
/**
* Before Validate Event
* @param model PlaitsModel - The form model
*/
this.on('beforeValidate', function (model) {
...
});
This even fires after a model has been validated.
/**
* After Validate Event
* @param model PlaitsModel - The form model
* @param validationResult Boolean - Whether the model is valid or not
* @param validationErrors Object - An object containing any validation errors
*/
this.on('afterValidate', function (model, validationResult, validationErrors) {
...
});
Plaits provides a middleware for Express that gives you the ability to render form fields automatically in your templates.
Plaits.ExpressMiddleware([options])
The middleware takes an options object, with the defaults:
{
name: 'Plaits', // Helper Name for res.locals
templatePaths: ['node_modules/plaits/lib/templates'], // Template Locations, see Html Templates
templateExtension: 'jade', // Template Extension, see Html Templates
renderSpecialAttributesValue: true, // Whether to Render Vals for Some Attributes (eg. muted)
errorCssClass: 'error', // Error CSS Class On Generated Form Elements
requiredCssClass: 'required', // Required CSS Class on Generated Form Elements
errorContainerTag: 'div', // Container Wrapper Tag For Generated Error Output
errorContainerClass: 'error-message', // Container Wrapper Class for firstErrorFor()
errorSummaryContainerClass: 'error-summary', // Container Class for Generated Error Summary
errorSummaryText: 'Please fix the following validation errors:' // Error Summary Text
}
See the below sections for further explanations on some of these options.
When using the Middleware specified above, it will add a helper to your res.locals
which is then available in your templates.
You can specify the name of this helper by passing the option name
as part of the Middleware, which defaults to Plaits
.
You can also use multiple middleware if you need different behaviour by specifying different names for each, for example:
// Plaits Frontend Middleware
app.use(Plaits.ExpressMiddleware());
// Plaits Admin Middleware
app.use(Plaits.ExpressMiddleware({name: 'PlaitsAdmin', requiredCssClass: 'required-input'}));
Each of the following helpers is accessible under the Html property of your middleware item;
// Defaults
Plaits.Html.textFieldFor(...)
// Using 'PlaitsAdmin'
PlaitsAdmin.Html.textFieldFor(...)
Renders a button.
button: function (label, [htmlAttributes])
Render a reset button.
resetButton: function (text, [htmlAttributes])
Render a submit button.
submitButton: function (text, [htmlAttributes])
Generates a label for a specified input.
If the field is required, it will contain <span>*</span>
next to the text to show the required state. It will also have the requiredCssClass
.
In the case that this field fails validation, it will also have errorCssClass
added.
labelFor: function (model, attribute, [htmlAttributes])
This will show the first error for the given model’s field/attribute.
The wrapping tag is specified by errorContainerTag
(defaults to div
) and the class will be errorContainerClass
(defaults to error-message
).
firstErrorFor: function (model, attribute, [htmlAttributes])
Generates a container with all errors for the given model’s field/attribute.
The wrapping tag is specified by errorContainerTag
(defaults to div
) and the class will be errorSummaryContainerClass
(defaults to error-summary
).
errorsFor: function (model, attribute, [htmlAttributes])
Generates an error summary with all errors for the entire model.
Takes an optional summaryText
parameter, which will be displayed at the top of the summary.
This defaults to ‘Please fix the following validation errors’, or whatever you have passed into the initial Middleware options.
errorSummary: function (model, [summaryText], [htmlAttributes])
Render a text input for the given model’s attribute.
textFieldFor: function (model, attribute, [htmlAttributes])
Render an email input for the given model’s attribute.
emailFieldFor: function (model, attribute, [htmlAttributes])
Render a text area for the given model’s attribute.
textAreaFor: function (model, attribute, [htmlAttributes])
Render a number input for the given model’s attribute.
numberFieldFor: function (model, attribute, [htmlAttributes])
Render a range input for the given model’s attribute.
rangeFieldFor: function (model, attribute, [htmlAttributes])
Render a color input for the given model’s attribute.
colorFieldFor: function (model, attribute, [htmlAttributes])
Render a search input for the given model’s attribute.
searchFieldFor: function (model, attribute, [htmlAttributes])
Render a date input for the given model’s attribute.
dateFieldFor: function (model, attribute, [htmlAttributes])
Render a time input for the given model’s attribute.
timeFieldFor: function (model, attribute, [htmlAttributes])
Render a tel input for the given model’s attribute.
telFieldFor: function (model, attribute, [htmlAttributes])
Render a url input for the given model’s attribute.
urlFieldFor: function (model, attribute, [htmlAttributes])
Render a hidden input for the given model’s attribute.
hiddenFieldFor: function (model, attribute, [htmlAttributes])
Render a password input for the given model’s attribute.
passwordFieldFor: function (model, attribute, [htmlAttributes])
Render a file input for the given model’s attribute.
fileFieldFor: function (model, attribute, [htmlAttributes])
Render a select field for the given model’s attribute.
Takes an items
parameter, which should be a key:value object specifying which items should be the options.
selectFor: function (model, attribute, items, [htmlAttributes])
Render a checkbox input for the given model’s attribute.
checkboxFor: function (model, attribute, [htmlAttributes])
Render a radio input for the given model’s attribute.
radioFor: function (model, attribute, [htmlAttributes])
Render multiple checkbox fields for the given model’s attribute.
Takes an items
parameter, which should be a key:value object specifying which items should be individually rendered.
checkboxListFor: function (model, attribute, items, [htmlAttributes])
Render multiple radio fields for the given model’s attribute.
Takes an items
parameter, which should be a key:value object specifying which items should be individually rendered.
radioListFor: function (model, attribute, items, [htmlAttributes])
In addition to the Html Helpers specified above, Plaits also comes with a set of ready-built Html templates that are wrappers for the above helpers.
The Html templates are built with Jade.
Each of the field helpers specified above has a corresponding template which contains a label, a field of the specified type, and will render any validation errors from that field.
The template functions are named the same as their helpers, only without the word ‘For’ in the function name, so email()
, text()
etc.
If you wish the view the default templates, they are in lib/templates
.
The templates are accessible inside your templates via your middleware, like so:
// Default 'Plaits'
Plaits.Html.Template.text(...)
Plaits.Html.Template.email(...)
Plaits.Html.Template.select(...)
// Different Name Specified For Middleware, e.g. 'PlaitsAdmin'
PlaitsAdmin.Html.Template.textArea(...)
PlaitsAdmin.Html.Template.number(...)
PlaitsAdmin.Html.Template.password(...)
The Plaits templates can be customised in a few different ways.
When specifying your middleware options for Plaits, it is possible to pass a custom templatePaths
option.
Plaits templates are cached at render time for performance, so you will need to restart your application server when changing the templates.
This option can be a single path, or an array, of locations where Plaits should look for form html templates:
// Resolve Path
var myTemplatePath: path.join(__dirname, 'views', 'forms');
// Use Middleware
app.use(Plaits.ExpressMiddleware({templatePaths: [myTemplatePath]));
Simply copy the templates you wish to override from lib/templates
to your new location - in the above example views/forms
.
When Plaits scans the directories for the requested template, e.g. the email template, it will prioritise the custom location over the default location,
and will render the one residing in views/forms
.
Since you may wish to have multiple versions of an template, e.g. different classes or wrappers, the Plaits middleware provides the following function:
/**
* Render a Custom Template.
* Takes template name, model, attribute and any additional parameters to pass to the template.
* @param templateName string
* @param model PlaitsModel
* @param attribute string
* @param additionalParams Object
* @return {*}
*/
render: function (templateName, model, attribute, [additionalParams])
This function will look for the template with templateName
and will render that template if found.
Use the additionalParams
parameter to pass any other parameters required for the rendering of the template, e.g. a list of items for a select
input.
While templates can have customisable file extensions (via the templateExtension
option passed to your middleware), the templates MUST
be in the Jade template language. While this is more opinionated that is pleasant, Jade is at least very well supported,
documented and tested.
Below is a full (although very simple) end-to-end example of creating, rendering and validating a Plaits model using Express.
Express app.js
, before routes:
// Require Plaits
var Plaits = require('plaits');
// Plaits Middleware
app.use(Plaits.ExpressMiddleware());
Model Declaration, living in forms/register.js
:
// Require Plaits
var Plaits = require('plaits');
// Register Form Declaration
var RegisterForm = Plaits.Model.extend(
{
// Form Name
name: 'register_form',
// Field List
fields: [
'username',
'email_address',
'password',
'confirm_password'
],
// Validators
validators: {
username: [
Plaits.Validators.required(),
Plaits.Validators.alphanumeric()
],
email_address: [
Plaits.Validators.required(),
Plaits.Validators.email()
],
password: [
Plaits.Validators.required(),
Plaits.Validators.minLength(8)
],
confirm_password [
Plaits.Validators.matchProperty('password')
]
}
}
);
// Export Form
module.exports = RegisterForm;
Route file, routes/account.js
:
// Require Form
var RegisterForm = require('../forms/register');
// Account Register Route - GET
router.get('/account/register', function (req, res) {
// New Form
var registerForm = new RegisterForm();
// Render Template, Passing Form
res.render('account/register', {
registerForm: registerForm
});
});
// Account Register Route - POST
router.post('/account/register', function (req, res) {
// New Form
var registerForm = new RegisterForm();
// Parse Request & Validate
registerForm.parseRequestSync(req).validate().then(function (result) {
// Valid?
if (result) {
// Do Register / Database Stuff Here
// ...
// Redirect
res.redirect('/account/register/success');
} else {
// Invalid, Re-Render The Template
res.render('account/register', {
registerForm: registerForm
});
}
}).catch(function (e) {
// Something Went Horribly Wrong, Caught A Rejected Promise
res.json(e);
});
});
Register template, account/register.jade
:
extends layout
block content
form(method='POST')
!=Plaits.Html.Template.text(registerForm, 'username')
!=Plaits.Html.Template.email(registerForm, 'email')
!=Plaits.Html.Template.password(registerForm, 'password')
!=Plaits.Html.Template.password(registerForm, 'confirm_password')
!=Plaits.Html.Template.submit()
And that is enough to render the form, handle the POST request, validate the form and display any validation errors to the user.
Here are a few things I plan on incorporating or working on the future.
Extra provided validators are always useful to prevent people from having to write their own, especially if tested and approved, for example:
A GitHub repository with some examples of using Plaits in different circumstances would be useful.
Fixed issue with radio input value comparisons incorrectly comparing types
Updated various dependencies
Added new function, model.hasFile(field)
, to easily check if a file has been submitted as part of the form request
Fixed issue with Plaits template function calls interfering with Express res.locals
Fixed issue with checkbox value comparisons not always comparing variable types properly
Fixed issue with labels returning undefined
Updated various dependencies
Added file validation support (required, minSize, maxSize, mimeTypes & enforceMimeMatch - see File Validators)
Added support for mapping file field values to their respective fields (see File Field Mapping)
Updated various dependencies (Namely lodash to v3)
Generated by aglio on 18 Jan 2016