aurelia-validatejs
Introduction
aurelia-validatejs is a new plugin for performing validation with Aurelia. It uses validate.js which is a proven, expressive validation library.
This post is a living, work in process documentation to give others an idea how things are working so far and how they can help with contributing (or how they can write their own validation library if they would like.
High-level view
Validation is comprised of five major components. To see the interfaces for each component take a look at aurelia-validation - https://github.com/aurelia/validation
Index
The index of any plugin is where it should implement a configure method. This is where you can do any setup. aurelia-validatejs uses the index.js to register handlers to override the base implementation when the developer imports ValidationReporter
or a Validator
.
ValidationEngine
Currently the validation engine is only in charge of finding and returning the proper ValidationReporter. This allows us to get the proper validation reporter instance for our model from anywhere in our codebase.
ValidationError
The validation error is an interface for what a validation error should look like. In aurelia-validatejs you can see we iterate over the properties of the object and transform them to match the interface. This keeps our errors consistent so that they could be provided by any form of validation.
ValidationReporter
The validation reporter is used to allow anyone to subscribe to errors that are reported on an object. This gives us the ability to show validation errors anywhere in our application, once we have access to the proper reporter instance.
aurelia-validatejs implements an observer that has a dispose method. This means when you .subscribe()
to the reporter an observer is added to the list of __callbacks__
. This is so when the .publish()
method is called, we iterate over all of the callbacks and publish changes to those subscribers.
A validation reporter is nice because it doesn't directly tie our code to error reporting by tacking on properties to the object. It uses a metadata approach.
Validator
The validator is the alternative approach to validation. We are building the fluent API for validation to use the validator so that validation can be manually triggered as well.
Non-standard classes
We also have a few non-standard classes that are specific to aurelia-validatejs.
ValidationRule
The validation rules are how aurelia-validatejs implements validate.js. Each rule is represents a form of validation that will be tested against on the property of an object. For example, each of the decorators currently has a rule backing it. For required
we use the RequiredRule
which creates a new validation rule.
The rule takes in a name and a config object. The config object is used by rqeuire.js to configure the validator.
TODO: Give some concreate examples here
ValidationConfig
The validation config is the interface that is used to keep all of the validation rules as well actually validate the target. When the .validate()
method is called on the config (for example on the setter in rules/base.js
) it validates the entire object. If you only wanted to validate and return errors for one property of the object you would pass in a second optional parameter with the name of the property.
The validation config is fetched from metadata using the getOrCreateOwn
method from aurelia-metadata. This allows the config to exist and be shared or grabbed from anywhere in the application.
aurelia-validatejs decorators
Right now all of the rules are in the rules directory. They are implemented through decorators in the decorators.js
. Each of the decorators calls the base
function from base.js
. This adds a getter and a setter on to the object for each of the properties being validated. When the setter is called it grabs the validation reporter and config and calls validate on the object.
To keep it simple and not worry about maintaining a cache of validated properties we validate all properties on the object. This ensures that all of the releveant properties are validated to handle things like dependencies and equality.