项目作者: on3iro

项目描述 :
Zero-dependency ES6 form field validation library
高级语言: JavaScript
项目地址: git://github.com/on3iro/vally.git
创建时间: 2018-02-03T12:05:36Z
项目社区:https://github.com/on3iro/vally

开源协议:MIT License

下载


Build Status
Coverage Status
npm version
Maintainability
JavaScript Style Guide

api docs
GitHub

vally

vally is a simple ES6, zero-dependency form field validation library, that helps
to determine if <input>-values pass certain tests.
The library just provides a set of useful helper functions. Most of the DOM-manipulation
and validation handling still lies in the hands of the user to ensure as much
flexibility as possible.

Installation

  1. npm i --save vally

You can either use the build from inside the dist/ directory and include
it via <script>-tag or use require / import-syntax in your code.

  1. <html lang="en">
  2. <head></head>
  3. <body>
  4. <script>
  5. vally.isString(1) // => false
  6. </script>
  7. </body
  8. <script src="./vally.min.js"></script>
  9. </html

or

  1. import { isString } from 'vally'
  2. isString(1) // => false

API

Docs

Configuration and API details can be found here:

API docs

FAQ

Why not just use HTML5 validation?

HTML5 validation sometimes is a bit lacking when it comes to customizability
and validating with custom constraints. That’s not to say it is bad - especially
since it is now supported by all major browsers.
In fact it is good practice to still use HTML5 type constraints on your fields
(i.e. type="number") in conjunction with vally to provide the best possible experience to your users.

How can i specify a field as required?

Just use the regular required-Attribute
on your <input>. This will ensure that vally actually validates the element if the input is empty.
You still have to specify validator functions to provide the actual validation functionality.
I.e. if the field should not be empty use isNoneEmptyString().

What happens to inputs that are not displayed?

Inputs that are not displayed (i.e. if display: none, type="hidden" or hidden="" is set), are
simply ignored by the validation.

How can I bind vally to certain events?

vally leaves most of the DOM-manipulation to the user. For simple bindings (i.e. for ‘keyup’-events)
however you can use initWithBindings(). For detailed explaination have a look at our examples below.

Why does vally ship so few validator functions?

Because validators in vally are simple functions it is very
easy to either write them yourself our just use a library like
validator.js.
Providing only a basic set of functions keeps the footprint of the library small.

How can I use a validator function with multiple arguments?

If you need multiple arguments (like some validator.js. functions need additional configuration) you can simply
partially apply the function and return a validator function.

Example:

  1. const isLessThan = (num: number) => (val: any):boolean => { /* actual implementation */ }

Examples

Simple Example

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8" />
  5. <meta name="viewport" content="width=device-width" />
  6. <title>Simple submit</title>
  7. <style>
  8. input {
  9. outline: none;
  10. box-shadow: none;
  11. }
  12. .error {
  13. background: red;
  14. }
  15. </style>
  16. </head>
  17. <body>
  18. <form class="myform" action="" method="">
  19. <label for="number">Some number:</label>
  20. <input id="number" type="text" name="number">
  21. <label for="mail">Mail*:</label>
  22. <input id="mail" type="text" name="email" required>
  23. <label for="custom">Custom (start with 'T')*:</label>
  24. <input id="custom" type="text" name="custom">
  25. <button id="submit" type="submit">Submit</button>
  26. </form>
  27. <script src="vally.min.js"></script>
  28. <script>
  29. const mail = document.getElementById('mail')
  30. const number = document.getElementById('number')
  31. const submit = document.getElementById('submit')
  32. const custom = document.getElementById('custom')
  33. if (mail && number && submit && custom) {
  34. submit.addEventListener('click', (e) => {
  35. e.preventDefault()
  36. // Simple custom validator function which ensures, that the value
  37. // starts with the character 'T'
  38. const startsWithT = (val) => val.charAt(0) === 'T'
  39. const result = vally.validate({
  40. fields: [
  41. {
  42. node: mail,
  43. validators: [ { fn: vally.isEmail } ]
  44. },
  45. {
  46. node: number,
  47. validators: [ { fn: vally.isNumberString } ]
  48. },
  49. {
  50. node: custom,
  51. validators: [ { fn: startsWithT }]
  52. }
  53. ]
  54. })
  55. // Set 'error' class to each invalid input
  56. result.validations.map(v => {
  57. if (!v.isValid) {
  58. v.node.classList.add('error')
  59. } else {
  60. v.node.classList.remove('error')
  61. }
  62. })
  63. })
  64. }
  65. </script>
  66. </body>
  67. </html>

Complex example

The following example shows how vally can be used to use the same configuration
to manually validate on the submit event and also bind it to
fire on keyup triggered by individual inputs.

index.html

Lets use almost the same markup as before… . This time we ship vally bundled together
with our other js resources in main.bundle.js, though. We also want to insert
custom error messages into the DOM depending on which validator for a field failed.
There are a lot of ways to achieve this. In this case we simply put hidden divs
below each input and toggle their display on validation.
Of course we also insert our custom messages into them.

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8" />
  5. <meta name="viewport" content="width=device-width" />
  6. <title>Simple submit</title>
  7. <style>
  8. input {
  9. outline: none;
  10. box-shadow: none;
  11. }
  12. .error {
  13. background: red;
  14. }
  15. .hidden {
  16. display: none;
  17. }
  18. </style>
  19. </head>
  20. <body>
  21. <form class="myform" action="" method="">
  22. <label for="number">Some number:</label>
  23. <input id="number" type="text" name="number">
  24. <div id="number-error" class="hidden"></div>
  25. <label for="mail">Mail(*):</label>
  26. <input id="mail" type="text" name="email" required>
  27. <div id="mail-error" class="hidden"></div>
  28. <label for="custom">Number below 10(*):</label>
  29. <input id="custom" type="text" name="custom" required>
  30. <div id="custom-error" class="hidden"></div>
  31. <button id="submit" type="submit">Submit</button>
  32. </form>
  33. <script src='./main.bundle.js'></script>
  34. </body>
  35. </html>

config.js

We separate our configuraion from the actual validation logic, to make everything
a bit more maintainable.

  1. // config.js
  2. import {
  3. createConfig,
  4. isEmail,
  5. isNoneEmptyString,
  6. isNumberString
  7. } from 'vally'
  8. // Custom validator
  9. // Because we need another parameter for our function to specify the threshold,
  10. // we simply curry our validator function. The actual invokation to get a
  11. // real validator function would look like this: isLessThan(10)
  12. const isLessThan = (num: number) => (val: any): boolean => {
  13. if (isNumberString(val)) return false
  14. return parseInt(val) < num
  15. }
  16. // Because we only want to fetch DOM-elements via document.querySelector
  17. // we can use the createConfig helper function to create a valid configuration.
  18. // Therefore we specify our specs with selectors, which in turn are used to
  19. // fetch the actual DOM nodes
  20. const specs = [
  21. {
  22. selector: '#mail',
  23. validators: [
  24. {
  25. fn: isNoneEmptyString,
  26. errorSelector: 'mail-error',
  27. msg: 'Please enter a value.'
  28. },
  29. {
  30. fn: isEmail,
  31. errorSelector: 'mail-error',
  32. msg: 'Please enter a valid email address.'
  33. }
  34. ]
  35. },
  36. {
  37. selector: '#number',
  38. validators: [{
  39. fn: isNumberString,
  40. errorSelector: 'number-error',
  41. msg: 'Please enter a number.'
  42. }]
  43. },
  44. {
  45. selector: '#custom',
  46. validators: [
  47. {
  48. fn: isNoneEmptyString,
  49. errorSelector: 'custom-error',
  50. msg: 'Please enter a value.'
  51. },
  52. {
  53. fn: isLessThan(10),
  54. errorSelector: 'custom-error',
  55. msg: 'Please enter a number smaller than ten.'
  56. }
  57. ]
  58. }
  59. ]
  60. export config = createConfig(specs)

index.js

Here we will define our actual validation logic.

  1. // index.js
  2. import {
  3. initWithBindings,
  4. validate
  5. } from 'vally'
  6. import { config } from './config'
  7. // Our callback will recieve a result object and act on its field validations
  8. const callback = (e: Event, { validations }: { validations: Valiations }): void => {
  9. validations.forEach(v => {
  10. const msgNode = document.getElementById(v.validator.errorSelector)
  11. if (v.isValid) {
  12. v.node.classList.remove('error')
  13. // Hide msg
  14. if (msgNode ) msgNode.classList.add('hidden')
  15. } else {
  16. v.node.classList.add('error')
  17. // Show error msg
  18. if (msgNode) {
  19. msgNode.classList.remove('hidden')
  20. msgNode.innerHTML = v.validator.msg
  21. }
  22. }
  23. })
  24. }
  25. // Create a pre-configured partially applied validate function that we can use
  26. // on our submit button. We technically don't need to do this
  27. // as we only need to validate on submit. But in a real-world application you might
  28. // need to re-use your validate function
  29. // and this makes it easier.
  30. const validateForm = () => validate(config)
  31. const init = () => {
  32. // Bind our callback to the keyup event on each individual field
  33. initWithBindings(config, 'keyup', callback, 100)
  34. // Bind our validate function to our submit button
  35. const btnSubmit = document.getElementById('submit')
  36. if (!btnSubmit) return
  37. btnSubmit.addEventListener('click', (e) => {
  38. e.preventDefault()
  39. const result = validateForm()
  40. if (result.isValid) {
  41. // logic to send our form
  42. } else {
  43. // React to our validation result
  44. callback(e, result)
  45. }
  46. })
  47. }
  48. init()