{"id":16464306,"url":"https://github.com/zhorton34/vuejs-form","last_synced_at":"2025-03-16T18:31:26.976Z","repository":{"id":49000680,"uuid":"260154955","full_name":"zhorton34/vuejs-form","owner":"zhorton34","description":"Vue Form with Laravel Inspired Validation and Simply Enjoyable Error Messages Api. (Form Api, Validator Api, Rules Api, Error Messages Api)","archived":false,"fork":false,"pushed_at":"2022-03-05T23:16:43.000Z","size":997,"stargazers_count":41,"open_issues_count":4,"forks_count":6,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-02-27T12:08:33.524Z","etag":null,"topics":["data-centric","javascript","js","react","reactivity","reactjs","vue"],"latest_commit_sha":null,"homepage":"https://cleancode.studio","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zhorton34.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-04-30T08:26:50.000Z","updated_at":"2023-12-26T18:17:27.000Z","dependencies_parsed_at":"2022-09-20T04:13:09.599Z","dependency_job_id":null,"html_url":"https://github.com/zhorton34/vuejs-form","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhorton34%2Fvuejs-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhorton34%2Fvuejs-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhorton34%2Fvuejs-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zhorton34%2Fvuejs-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zhorton34","download_url":"https://codeload.github.com/zhorton34/vuejs-form/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243826788,"owners_count":20354220,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-centric","javascript","js","react","reactivity","reactjs","vue"],"created_at":"2024-10-11T11:26:57.375Z","updated_at":"2025-03-16T18:31:25.944Z","avatar_url":"https://github.com/zhorton34.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Travis](https://img.shields.io/travis/zhorton34/vuejs-form/master.svg?style=flat-square)](https://travis-ci.org/zhorton34/vuejs-form/builds)\n[![npm downloads](https://img.shields.io/npm/dm/vuejs-form.svg?style=flat-square)](http://badge.fury.io/js/vuejs-form)\n[![npm license](https://img.shields.io/npm/l/vuejs-form.svg?style=flat-square)](http://badge.fury.io/js/vuejs-form)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)\n[![dependencies](https://img.shields.io/badge/dependencies-none-brightgreen.svg?style=flat-square)](https://github.com/zhorton34/vuejs-form/blob/master/package.json)\n[![npm version](https://img.shields.io/npm/v/vuejs-form.svg?style=flat-square)](http://badge.fury.io/js/vuejs-form)\n[![Twitter Follow](https://img.shields.io/twitter/follow/cleancodestudio.svg?style=social)](https://twitter.com/cleancodestudio) \n[![Open Source Love svg1](https://badges.frapsoft.com/os/v1/open-source.svg?v=103)](https://github.com/ellerbrock/open-source-badges/)\n[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://GitHub.com/Naereen/StrapDown.js/graphs/commit-activity)\n\n\n## \u003cimg src='https://api.github.com/images/icons/emoji/coffee.png' height='50' width='50' alt=\"waving that vuejs form introduction \u0026 purpose title\"/\u003e That Vue Form \n\n![Vue Form AKA Vuejs Form Mission Statement For Building Vue Validation \u0026 Javascript Validated Forms](https://github.com/zhorton34/vuejs-form/raw/master/bundler/vuejs-form-purpose-statement.png \"Vue JS Form Package Purpose Journal Text\")\n\n\n\n\n\n\n\n\n\n\n---\n\n## \u003cimg src='https://api.github.com/images/icons/emoji/point_down.png' height=\"50\" width='50' alt='coffee icon vuejs form installation title'/\u003e Installation\n\n\n\n### NPM\n\n```bash\nnpm install --save-dev vuejs-form\n```\n\n### Yarn\n\n```bash\nyarn add vuejs-form --save\n```\n\n### CDN\n\n```bash\n\u003cscript src='https://unpkg.com/vuejs-form@latest/build/vuejs-form.min.js'\u003e\u003c/script\u003e\n```\n\n---\n\n## \u003cimg src='https://api.github.com/images/icons/emoji/coffee.png' height=\"50\" width='50' /\u003e Four Official Apis\n\n---\n\n- [Form Api](#form-api)\n- [Rules Api](#rules-api)\n- [Validator Api](#validator-api)\n- [Error Messages Api](#error-messages-api)\n\n\n---\n\n## Playground Examples\nCurious, but not 100% on whether this is what you're looking for?\nTry vuejs-form out for yourself before installing -- here's some live examples ready for you to tinker away at! \n\n---\n- [Example One (Validate Form On Each User Submit)](https://codepen.io/zhorton34/pen/zYvWZYz)\n- [Example One (Validate Form On Each User Update)](https://codepen.io/zhorton34/pen/xxwaYez)\n---\n\n## Simple Vue Example\n\n---\n```html\n\u003ctemplate\u003e\n    \u003cdiv\u003e        \n        \u003cinput type='email' v-model='form.email' placeholder=\"Email\"/\u003e\n        \u003cspan v-if=\"form.errors().has('email')\"\u003e\n            {{ form.errors().get('email') }}\n        \u003c/span\u003e\n\n        \u003cinput type='password' v-model='form.password' placeholder=\"Password\"/\u003e\n        \u003cspan v-if=\"form.errors().has('password')\"\u003e\n            {{ form.errors().get('password') }}\n        \u003c/span\u003e\n\n        \u003cinput type='password' v-model='form.password_confirmation' placeholder=\"Confirm Password\"/\u003e \n\n        \u003cbutton :disabled='form.empty()' @click='submit'\u003eSubmit\u003c/button\u003e\n    \u003c/div\u003e\n\u003c/template\u003e\n```\n```js\nimport form from 'vuejs-form'\n\nexport default {\n    data: () =\u003e ({\n        form: form({\n            email: '', \n            password: '', \n            password_confirmation: '' \n        })\n        .rules({\n            email: 'email|min:5|required',\n            password: 'required|min:5|confirmed'\n        })\n        .messages({\n            'email.email': 'Email field must be an email (durr)',\n            'password.confirmed': 'Whoops, :attribute value does not match :confirmed value',\n        }),\n   }),\n\n    methods: {\n        submit() {\n            if (this.form.validate().errors().any()) return;\n            \n            alert('Success, form is validated!');\n\n            console.log('form all(): ', this.form.all());\n            console.log('form except(): ', this.form.except('password_confirmation'));\n        },\n    }\n}\n```\n\n---\n\n## Vue Example Two\n\n---\n\n\n---\n\n## Form API\n\n---\n\n- [all](#all)\n- [boolean](#boolean)\n- [empty](#empty)\n- [except](#except)\n- [fill](#fill)\n- [filled](#filled)\n- [forget](#forget)\n- [has](#has)\n- [hasAny](#hasany)\n- [input](#input)\n- [keys](#keys)\n- [make](#make)\n- [missing](#missing)\n- [only](#only)\n- [set](#set)\n- [toArray](#toarray)\n- [wrap](#wrap)\n- **Extending Form Api**\n- [macro](#macros)\n- [localMacro](#macros)\n- [forceMacro](#macros)\n- [forceLocalMacro](#macros)\n\n---\n\n## Error Messages Api\n\n---\n\n- [form.errors().any()](#any-errors)\n- [form.errors().all()](#all-errors)\n- [form.errors().list()](#list-errors)\n- [form.errors().set(errors)](#set-errors)\n- [form.errors().forget()](#forget-errors)\n- [form.errors().has(field)](#has-error)\n- [form.errors().get(field)](#get-error)\n- [form.errors().list(field)](#list-error)\n- [form.errors().add(field, message)](#add-error)\n- [form.errors().set(field, messages)](#set-field-errors)\n- [form.errors().forget(field)](#forget-field)\n- [form.errors().getValidator()](#get-errors-validator)\n- **Extending Errors Api**\n- [form.errors().macro(name, fn)](#macros)\n- [form.errors().forceMacro(name, fn)](#macros)\n- [form.errors().localMacro(name, fn)](#macros)\n- [form.errors().forceLocalMacro(name, fn)](#macros)\n\n\n---\n\n## Validator Api\n\n---\n\n- [form.rules({...})](#form-register-rules)\n- [form.messages({...})](#form-customize-error-messages)\n- [form.hasValidator()](#form-has-validator)\n- [form.setValidator({...})](#form-set-rules)\n- [form.validator()](#form-validator-instance)\n- [form.validate()](#validate-form-data)\n- **Validator Hooks (Documentation Stored in Vuejs Validators Repository)**\n- [form.validator().before(callbackHook) (see vuejs-validators repo)](https://github.com/zhorton34/vuejs-validators)\n- [form.validator().after(callbackHook) (see vuejs-validators repo)](https://github.com/zhorton34/vuejs-validators)\n- [form.validator().passed(callbackHook) (see vuejs-validators repo)](https://github.com/zhorton34/vuejs-validators)\n- [form.validator().failed(callbackHook) (see vuejs-validators repo)](https://github.com/zhorton34/vuejs-validators)\n- [form.validator().validateWithoutHooks() (see vuejs-validators repo)](https://github.com/zhorton34/vuejs-validators)\n- **Extend Validator Api**\n- [form.validator().macro(name, fn)](#macros)\n- [form.validator().forceMacro(name, fn)](#macros)\n- [form.validator().localMacro(name, fn)](#macros)\n- [form.validator().forceLocalMacro(name, fn)](#macros)\n\n---\n\n## Rules Api\n\n---\n- [accepted](#accepted-rule)\n- [alpha](#alpha-rule)\n- [alpha_dash](#alpha_dash-rule)\n- [alpha_num](#alpha_num-rule)\n- [array](#array-rule)\n- [between](#between-rule)\n- [boolean](#boolean-rule)\n- [confirmed](#confirmed-rule)\n- [date](#date-rule)\n- [date_equals](#date-equals-rule)\n- [before (date)](#before-rule)\n- [before_or_equal (date)](#before-or-equal-rule)\n- [after (date)](#after-rule)\n- [after_or_equal (date)](#after-or-equal-rule)\n- [greater_than (numeric)](#greater-than-rule)\n- [gte (Greater than or equal numeric)](#gte-rule)\n- [less_than (numeric)](#less-then-rule)\n- [lte (Less than or equal numeric)](#lte-rule)\n- [different](#different-rule)\n- [digits](#digits-rule)\n- [digits_between](#digits_between-rule)\n- [distinct](#distinct-rule)\n- [email](#email-rule)\n- [ends_with](#ends_with-rule)\n- [integer](#integer-rule)\n- [ip](#ip-rule)\n- [ipv4](#ipv4-rule)\n- [ipv6](#ipv6-rule)\n- [json](#json-rule)\n- [max](#max-rule)\n- [min](#min-rule)\n- [not_regex](#not_regex-rule)\n- [not_within](#not_within-rule)\n- [number](#number-rule)\n- [numeric](#numeric-rule)\n- [phone](#phone-rule)\n- [regex](#regex-rule)\n- [required](#required-rule)\n- [same](#same-rule)\n- [starts_with](#starts_with-rule)\n- [string](#string-rule)\n- [url](#url-rule)\n- [within](#within-rule)\n\n\n\n\n---\n\n## Quick Vue Example\n\n---\n\n```html\n\u003ctemplate\u003e\n    \u003cdiv\u003e\n        \u003cdiv v-if=\"form.errors().any()\" v-for=\"(message, key) in form.errors().list()\" :key=\"`${key}.error`\"\u003e\n            {{ message }}\n        \u003c/div\u003e\n\n        \u003cinput type='text' v-model='form.name' /\u003e \u003cbr\u003e\n        \u003cinput type='email' v-model='form.email' /\u003e \u003cbr\u003e\n        \u003cinput type='password' v-model='form.password' /\u003e \u003cbr\u003e\n        \u003cinput type='password' v-model='form.confirm_password' /\u003e \u003cbr\u003e\n        \u003chr\u003e\n        \u003cbutton :disabled='form.empty()' @click='submit'\u003e\n            Complete\n        \u003c/button\u003e\n    \u003c/div\u003e\n\u003c/template\u003e\n```\n```js\nimport form from 'vuejs-form'\n\nexport default {\n    data: () =\u003e ({\n        form: form({\n            email: '',\n            password: '',\n            confirm_password: ''\n        })\n        .rules({\n            email: 'email|min:5|required',\n            password: 'same:confirm_password',\n            confirm_password: 'min:6|required',\n        })\n        .messages({\n            'email.required': ':attribute is required',\n            'email.email': ':attribute must be a valid email',\n            'email.min': ':attribute may not have less than :min characters',\n            'password.same': 'Whoops, :attribute does not match the :same field',\n        }),\n   }),\n\n   watch: {\n       /*--------------------------------------------------------------\n        * When Should Your Form \"Validate\", Providing Error Messages?\n        *--------------------------------------------------------------\n        * Form validates every time form data is updated. To\n        * display errors on form submit, remove watcher \u0026\n        * move \"this.form.validate()\" over to submit()\n        *--------------------------------------------------------------\n        */\n        ['form.data']: {\n            deep: true,\n            immediate: false,\n            handler: (now, old) =\u003e { this.form.validate(); },\n        }\n   },\n\n    methods: {\n        failed() {\n            console.log('errors: ', this.form.errors().all());\n        },\n        passed() {\n            console.log('data: ', this.form.all());\n            console.log('wrapped data: ', this.form.wrap('data'));\n        },\n        submit() {\n            return this.form.errors().any() ? this.failed() : this.passed();\n        },\n    }\n}\n```\n\n\n---\n\n## Validator Api\n\n---\n\n- [form.rules({...})](#form-register-rules)\n- [form.messages({...})](#form-customize-error-messages)\n- [form.validator(...)](#form-validator-instance)\n- [form.validate(...)](#validate-form-data)\n- [form.hasValidator()](#form-has-validator)\n- [form.setValidator({...})](#form-set-rules)\n\n### Form Register Rules\n\u003e [@SeeAvailableValidationRules](#rules-api)  \n```js \nform(data).rules({\n    name: 'required|min:4',\n    link: 'required|url',\n    category: 'required|within:blue,reg,green'\n});\n```\n\n\u003e\n\u003e Optionally Use Arrays Syntax Instead Of Pipes\n\u003e\n\n```js \nform(data).rules({\n    name: ['required', 'min:4'],\n    link: ['required', 'url'],\n    category: ['required', 'within:blue,reg,green']\n});\n```\n\n### Form Customize Error Messages\n- All rules have global default error messages shown when rule fails validation.\n- Optionally, you are able to override the global defaults rule messages\n- Simply use the form(data).rules(set)`.messages({ '{field}.{rule}': 'custom message for failing rule on field' });`\n```js\nlet data = { email: ['required', 'email'] }\nform({ email: 'chad'}).rules({\n    email: ['required', 'email']\n})\n.messages({\n    'email.required': 'Email field is called email, needa make it an email (Hence Email Field Name, dont worry ~ we added validation just in case you forgot to make the email field an email)'\n})\n```\n### Form Validator Instance\n- Get [Validator Instance](https://github.com/zhorton34/vuejs-validators.js)\n```js\nform(data).rules(options).messages(customMessages);\n\n// form.validator().addMessage(field, error)\n// form.validator().addRule(field, rules) \n// etc...\n```\n\n### Validate Form Data\n- Check current form data against associated form rules\n- IMPORTANT: form MUST call validate() method before retrieving current errors\n\n\u003cu\u003e_COMMON GOTCHA!!!!_\u003c/u\u003e\n- This wont get the current form errors\n- The `form.validate()` method was Never called\n```js \nlet data = { name: '' };\nlet rules = { name: 'required' };\n\nform(data).rules(rules).errors().list();\n\n// --------------------------------------------\n// Form SHOULD fail, but errors list is empty\n// --------------------------------------------\n// Output: []\n// --------------------------------------------\n```\n\n\u003e _What's the reason?_ \n\u003e\n\u003e Retrieving errors before validating form data  \n\u003e \n\u003e would retrieve our error messages Api instance, \n\u003e but it hasn't been filled with our forms error messages.\n\u003e\n\u003e form.validate() compares form data against form rules, populating our form errors with failing rule messages.\n\u003e\n\n**Validate THEN resolve the errors (Using forms fluent api)**\n```js \nlet data = { name: '' };\nlet rules = { name: 'required' };\n\nform(data).rules(rules).validate().errors().list();\n// Output: ['Name field is required']\n\n// Again, we'll need to validate before retrieving our \n// errors to validate that the values passes our given rules\nform.name = 'hello world';\n\nform.errors().list();\n// Output: ['Name field is required']\n\nform.validate().errors().list();\n// Output: []; \n```\n\u003e\n\u003e\n\u003e Fluently call validate() before calling errors() is simple and to the point. \n\u003e\n\u003e At first, this may seem like a tedious extra step. Many may wonder why we don't simply auto-validate the data?\n\nReason for `form.validate().errors()` Instead of simply `form.errors()` triggering the validation.\n  - Reactive frameworks may use `errors()` and the associated Error Messages Api ([@See Form Error Messages Api](#form-error-messages-api))\n  - Without providing the option for the end developer to determine when the form validates\n  - Async requests, only validate once we've resolved some given data\n  - Immediate display of errors (Not always wanted)\n  - Option Open To Immediately show error messages ([@See Vue Watcher Example](#vue-example-two))\n  - Some other developers may only want to validate data on form submission\n  - Many validation rules can be abstracted using the form Api to simply disable the ability to submit a button\n  - EX: `\u003cbutton :disabled='form.empty()' @click='submit'\u003e Done \u003c/button\u003e`\n  - Then within `submit() method` simply run `if (this.form.validate().errors().any()) return;`\n  - That allows the option to set up vuejs-form more like a traditional Form, and avoid many complexities that come along with maintaining the status of our reactive state\n  - etc...\n  \n### Form Has Validator\nDetermine if form has a validator instance attached to it\n```js \nform.hasValidator(); // true or false\n```\n\n### Form Set Validator\n- Set Validator Instance\n- Optionally import the validator instance itself, and extend \n  its functionality validator().macro(add_method, method).\n- Then use form macros to track the current step form.macro(add_method, method).\n- vuejs-validators.js Also has validator life cycle hooks documented that are available here, but only documented within vuejs-form.js. Very helpful for multi-step forms\n\n```js\nconst { form, validator } = require('vuejs-form');\n\n\nform().macro('setSwitchableValidators', (first, second) =\u003e {\n    this.toggleValidators = \n    this.toggleBetween = first\n});\n\n```  \n## Rules Api\n- [accepted](#accepted-rule)\n- [date](#date-rule)\n- [date_equals](#date-equals-rule)\n- [before (date)](#before-rule)\n- [before_or_equal (date)](#before-or-equal-rule)\n- [after (date)](#after-rule)\n- [after_or_equal (date)](#after-or-equal-rule)\n- [greater_than (numeric)](#greater-than-rule)\n- [gte (Greater than or equal numeric)](#gte-rule)\n- [less_than (numeric)](#less-then-rule)\n- [lte (Less than or equal numeric)](#lte-rule)\n- [alpha](#alpha-rule)\n- [alpha_dash](#alpha_dash-rule)\n- [alpha_num](#alpha_num-rule)\n- [array](#array-rule)\n- [between](#between-rule)\n- [boolean](#boolean-rule)\n- [confirmed](#confirmed-rule)\n- [different](#different-rule)\n- [digits](#digits-rule)\n- [digits_between](#digits_between-rule)\n- [distinct](#distinct-rule)\n- [email](#email-rule)\n- [ends_with](#ends_with-rule)\n- [integer](#integer-rule)\n- [ip](#ip-rule)\n- [ipv4](#ipv4-rule)\n- [ipv6](#ipv6-rule)\n- [json](#json-rule)\n- [max](#max-rule)\n- [min](#min-rule)\n- [not_regex](#not_regex-rule)\n- [not_within](#not_within-rule)\n- [number](#number-rule)\n- [numeric](#numeric-rule)\n- [phone](#phone-rule)\n- [regex](#regex-rule)\n- [required](#required-rule)\n- [same](#same-rule)\n- [starts_with](#starts_with-rule)\n- [string](#string-rule)\n- [url](#url-rule)\n- [within](#within-rule)\n\n\n\n### Date Equals Rule\n(Date)\nThe field under validation must be the same date as the rules date\n\n\u003e Passes Date Equals Rule\n```js\nlet form = { \n    one: '4-22-1997',\n    two: 'April 22 2025' \n}\n\nlet rules = {\n  one: 'date_equals:4-22-1997',\n  two: 'date_equals:April 22 2025',\n}\n```\n\n\u003e Fails Date Equals Rule\n```js\nlet form = { \n    one: '4-22-1997',\n    two: '2-12-1997' \n}\n\nlet rules = {\n  one: 'date_equals:4-24-1998',\n  two: 'date_equals:1-11-1996',\n}\n```\n\n### Before Rule\n(Date)\n\nThe Field under evaluation must be before the compared date\n\n\u003e Passes Before (Date) Rule\n```\nlet form = { \n    one: '4-22-1997', \n    two: '2-12-1997' \n}\n\nlet rules = {\n  one: 'before:4-22-1998',\n  two: 'before:2-12-1997',\n}\n```\n\n\u003e Fails Before (Date) Rule\n```js\nlet form = { \n    one: '4-22-1997', \n    two: '3-12-1997' \n}\n\nlet rules = {\n  one: 'before:4-22-1997',\n  two: 'before:2-3-1996',\n}\n```\n\n### Before Or Equal Rule\n(Date)\nThe field under validation must be before or equal to the compared date.\n\n\u003e Passes Before Or Equal (Date) Rule\n```js\nlet form = { \n    one: '4-22-1997', \n    two: '2-12-1997' \n}\n\nlet rules = {\n  one: 'before_or_equal:3-21-1998',\n  two: 'before_or_equal:2-12-1997',\n}\n```\n\n\u003e Fails Before Or Equal (Date) Rule\n```js\nlet form = { \n    one: '4-22-1997', \n    two: '2-3-1997' \n}\n\nlet rules = {\n  one: 'before_or_equal:4-23-1997',\n  two: 'before_or_equal:2-3-1996',\n}\n```\n\n### After Rule\n(Date)\n\nThe Field under evaluation must be after the compared date\n\n\u003e Passes After (Date) Rule\n```js\nlet form = { \n    one: '4-22-1997', \n    two: '2-2-1997' \n}\n\nlet rules = {\n  one: 'after:4-23-1997',\n  two: 'after:2-3-1996',\n}\n```\n\n### Date Rule\n(Date)\nThe field under validation must be a valid, non-relative date according to the new Date js constructor.\n\n\u003e Passes Date Rule\n- 4.22.1997 \n- 4-22-1997\n- 4/22/1997\n- April 22 1997\n- Tuesday April 22 1997\n\n\u003e Fails Date Rule\n- asdfweadf\n- 23423423\n- []\n\n\u003e Fails After (Date) Rule\n```js\nlet form = { \n    one: '4-22-1997', \n    two: '2-12-1997' \n}\n\nlet rules = {\n  one: 'after:4-22-1998',\n  two: 'after:1-11-1996',\n}\n```\n\n\n### After Or Equal Rule\n(Date)\nThe field under validation must be after or equal to the compared date.\n\n\u003e Passes After Or Equal (Date) Rule\n```js\nlet form = { \n    one: '4-22-1997',\n    two: '1-11-2013', \n}\n\nlet rules = {\n  one: 'after_or_equal:4-22-1997',\n  two: 'after_or_equal:2-12-2014',\n}\n```\n\n\u003e Fails After Or Equal (Date) Rule\n```js\nlet form = { \n    one: '4-22-1997',\n    two: '2-12-1997' \n}\n\nlet rules = {\n  one: 'after_or_equal:4-23-1997',\n  two: 'after_or_equal:2-3-1996',\n}\n```\n\n\n### Accepted Rule\n\nThe field under form must be yes, on, 1, or true. This is useful for validating \"Terms of Service\" acceptance.\n\n\u003e Passing Accepted Rule\n```js\nlet data = { terms_of_service: 'no' };\nlet rules = { terms_of_service: 'accepted' };\n\n// false\nform(data).rules(rules).validate().errors().has('terms_of_service');\n```\n\n\u003e Failing Accepted Rule\n```js\nlet data = { terms_of_service: null }\nlet rules = { terms_of_service: 'accepted' }\n\n// true\nform(data).rules(rules).validate().errors().has('terms_of_services');\n```\n\n\n### Alpha Rule\nThe field under form must be entirely alphabetic characters.\n\n\u003e Passing Alpha Rule\n```js\nlet data = { letters: 'asdeddadfjkkdjfasdf' };\nlet rules = { letters: ['alpha'] };\n\n// false\nform(data).rules(rules).validate().errors().has('letters');\n```\n\n\u003e Failing Alpha Rule\n```js\nlet data = { letters: '5-@'}\nlet rules = { letters: ['alpha'] }\n\n// true\nform(data).rules(rules).validate().errors().has('letters');\n```\n\n### Alpha Dash Rule\nThe field under form may have alpha-numeric characters, as well as dashes and underscores.\n\n\u003e Passing Alpha Dash Rule\n\n```js\nlet data = { slug: 'user_name' };\nlet rules = { slug: ['alpha_dash'] };\n\n// false\nform(data).rules(rules).validate().errors().has('slug');\n```\n\n\u003e Failing Alpha Dash Rule\n```js\nlet data = { words: 'hello world'}\nlet rules = { words: ['alpha_dash'] }\n\n// true\nform(data).rules(rules).validate().errors().has('words');\n```\n\n### Alpha Num Rule\nThe field under form must be entirely alpha-numeric characters.\n\n\u003e Passing Alpha Num Rule\n\n```js\nlet data = { key: '4asdasdfe4d23545w634adf' };\nlet rules = { key: ['alpha_num'] };\n\n// false\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Alpha Num Rule\n```js\nlet data = { identifier: '1-asdf4adf_d_42'}\nlet rules = { identifier: ['alpha_num'] }\n\n// true\nform(data).rules(rules).validate().errors().any();\n```\n\n### Array Rule\nThe field under form must be a JS array.\n\n\u003e Passing Array Rule\n```js\nlet data = { list: ['banana', 'broccoli', 'carrot'] };\nlet rules = { list: 'array' };\n\n// false \nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Array Rule\n```js\nlet data = { options: { name: 'hey world' } }\nlet rules = { options: 'array' }\n\n// true\nform(data).rules(rules).validate().errors().any();\n```\n\n\n### Email Rule\nThe given field value must be an email\n\n\u003e Passing Email Rule\n```js\nlet data = { email: 'example@cleancode.studio' };\nlet rules = { email: ['email'] };\n\n// false\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Email Rule\n```js\nlet data = { email: 'asdfsdaf@.net'}\nlet rules = { email: ['email'] }\n\n// true\nform(data).rules(rules).validate().errors().any();\n```\n\n\n### Boolean Rule\n- Boolish form, not strict boolean check \n- Validates that field value is \"truthy\" or \"falsy\"\n\n|**Truthy**|**Falsy**|\n|---|---|\n|1|0|\n|\"1\"|\"0\"|\n|\"on\"|\"off\"|\n|\"On\"|\"No\"|\n|\"ON\"|\"OFF\"|\n|\"yes\"|\"no\"|\n|\"Yes\"|\"Off\"|\n|\"YES\"|\"NO\"|\n|true|false|\n|\"true\"|\"false\"|\n|\"True\"|\"False\"|\n|\"TRUE\"|\"FALSE\"|\n\n\u003e Passing Boolean Rule\n```js\nlet data = { selected: 'Yes' };\nlet rules = { selected: ['boolean'] };\n\n// false\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Boolean Rule\n```js\nform = { selected: null };\nrules = { selected: ['boolean'] };\n\n// true\nform(data).rules(rules).validate().errors().any();\n```\n\n\n### Confirmed form Rule\n- `{field}` value must match `{field}_confirmation` value\n- Example `password` must match `password_confirmation` value to pass `confirmed` ruled\n\u003e Passing Confirmed Rule\n```js bash\nlet data = { password: 'secret', password_confirmation: 'secret' }\nlet rules = { password: 'confirmed' }\n\n// false\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Confirmed Rule\n```js bash\nlet data = { password: 'secret' };\nlet rules = { password: 'confirmed' };\n\n// true\nform(data).rules(rules).validate().errors().any();\nform.password_confirmation = 'something_something';\n\n// true\nform.validate().errors().any();\n```\n\n\u003e Passing Confirmed Rule Again\n```js bash \nform.password_confirmation = 'secret';\n\n// false\nform.validate().errors().any();\n```\n\n### Greater Than Rule\n(Numeric)\n\nNumber must be greater than compared value\n\n\u003e Passing greater than rule\n```js\n\nlet form = {\n    age: 24,\n    members: 19,\n    percentage: 0.4,\n};\n\nlet rules = {\n    age: 'greater_than:13',\n    members: 'greater_than:10',\n    percentage: 'greater_than:0.35',\n};\n```\n\n\u003e Failing greater than rule\n```js\n let form = {\n     age: 24,\n     members: 19,\n     percentage: 0.4,\n };\n \n let rules = {\n     age: 'greater_than:24',\n     members: 'greater_than:100',\n     percentage: 'greater_than:0.9',\n };\n```\n\n### Gte Rule\n(Greater Than Or Equal - Numeric)\nNumber must be greater than or equal to compared value\n\n\u003e Passing greater than or equal rule (gte)\n```js\n\nlet form = {\n    age: 24,\n    members: 19,\n    percentage: 0.4,\n};\n\nlet rules = {\n    age: 'gte:24',\n    members: 'gte:10',\n    percentage: 'gte:0.35',\n};\n```\n\n\u003e Failing greater than or equal rule (gte)\n```js\n \n let form = {\n     age: 24,\n     members: 19,\n     percentage: 0.4,\n };\n \n let rules = {\n     age: 'greater_than:25',\n     members: 'greater_than:100',\n     percentage: 'greater_than:0.9',\n };\n```\n\n### Less Than Rule\n(Numeric)\n\nNumber must be less than compared value\n\n\u003e Passing less than rule\n```js\n\nlet form = {\n    age: 24,\n    members: 19,\n    percentage: 0.4,\n} ;\n\nlet rules = {\n    age: 'less_than:25',\n    members: 'less_than:20',\n    percentage: 'less_than:0.8',\n}\n```\n\n\u003e Failing less than rule\n```js\n let form = {\n     age: 24,\n     members: 19,\n     percentage: 0.4,\n };\n \n let rules = {\n     age: 'less_than:24',\n     members: 'less_than:10',\n     percentage: 'less_than:0.1',\n }\n```\n\n\n### Lte Rule\n(Less than or equal - Numeric)\n\nNumber must be less than or equal to compared value\n\n\u003e Passing Less than or equal (lte) rule\n```js\n\nlet form = {\n    age: 24,\n    members: 19,\n    percentage: 0.4,\n} ;\n\nlet rules = {\n    age: 'lte:24',\n    members: 'lte:20',\n    percentage: 'lte:0.8',\n}\n```\n\n\u003e Failing less than or equal (lte) rule\n```js\n let form = {\n     age: 24,\n     members: 19,\n     percentage: 0.4,\n };\n \n let rules = {\n     age: 'less_than:24',\n     members: 'less_than:10',\n     percentage: 'less_than:0.5',\n }\n```\n\n### Different form Rule\nThe given field value is different than another field value\n\n\u003e Passing Different Rule\n```js bash\nlet data = { password: 'asdfasdfasdf', confirm_password: 'secret' };\nlet rules = { password: 'different:confirm_password' };\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Different Rule\n```js bash\nlet data = { password: 'secret', confirm_password: 'secret' }\nlet rules = { password: 'different:confirm_password' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\n### Digits Rule\nThe field under form must be numeric and must have an exact length of value.\n\n\u003e Passing Digits Rule\n```js\nlet data = { amount: '10000' }\nlet rules = { amount: 'digits:6' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Digits Rule\n```js\nlet data = { amount: '10000' }\nlet rules = { amount: 'digits:4' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n### Digits Between Rule\nThe field under form must be numeric and have a length between the lower and upper limit defined.\n\n\u003e Passing Digits Between Rule\n```js\nlet data = { amount: '10000' }\nlet rules = { amount: 'digits_between:4,6' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Digits Between Rule\n```js\nlet data = { amount: '10000' }\nlet rules = { amount: 'digits_between:3,5' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n### Distinct Rule\nThe field under form must be an array with no duplicate values.\n\n\u003e Passing Distinct Rule\n```js\nlet data = { shopping_list: ['ham', 'eggs', 'milk', 'turkey'] }\nlet rules = { shopping_list: 'distinct' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Distinct Rule\n```js\n\nlet data = { shopping_list: ['ham', 'ham', 'eggs', 'milk', 'turkey'] }\nlet rules = { shopping_list: 'distinct' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n### Email Rule\nThe given field value must be an email\n\n\u003e Passing Email Rule\n```js\nlet data = { email: 'example@cleancode.studio' };\nlet rules = { email: ['email'] };\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Email Rule\n```js\nlet data = { email: 'asdfsdaf@.net'}\nlet rules = { email: ['email'] }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n### Ends With Rule\nThe field under form must end with one of the given values.\n\n\u003e Passing Ends With Rule\n```js\nlet data = { name: 'sammie' };\nlet rules = { name: 'ends_with:sl,ie,asx' };\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Ends With Rule\n```js\nlet data = { name: 5 };\nlet rules = { name: 'ends_with:sl,ie,asx' };\n\nform(data).rules(rules).validate().errors().any();\n\nform.setData({ name: 'azure' }).setRules({ name: 'ends_with:sl,ie,asx' })\n    \nform.validate().errors().any();\n```\n\n\n### Integer Rule\nThis form rule does not verify that the input is of the \"integer\" variable type, only that the input is a string or numeric value that contains an integer.\n\n\u003e Passing Integer Rule\n```js\nlet data = { students: 25 }\nlet rules = { students: ['integer'] }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Integer Rule\n```js\nlet data = { students: 'yes' }\nlet rules = { students: ['integer'] }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n### IP Rule\nThis form rule confirms that value is an IP address.\n\n\u003e Passing IP Rule\n- \"115.42.150.37\"\n- \"192.168.0.1\"\n- \"110.234.52.124\"\n- \"2001:0db8:85a3:0000:0000:8a2e:0370:7334\" (Ipv6)\n\n\u003e Failing IP Rule\n- \"210.110\" – must have 4 octets\n- \"255\" – must have 4 octets\n- \"y.y.y.y\" – the only digit has allowed\n- \"255.0.0.y\" – the only digit has allowed\n- \"666.10.10.20\" – digit must between [0-255]\n- \"4444.11.11.11\" – digit must between [0-255]\n- \"33.3333.33.3\" – digit must between [0-255]\n\n\n### IPv4 Rule\nThis form rule confirms that value is an IPv4 address.\n\n\u003e Passing IPv4 Rule\n- \"115.42.150.37\"\n- \"192.168.0.1\"\n- \"110.234.52.124\"\n\n\u003e Failing IPv4 Rule\n- \"210.110\" – must have 4 octets\n- \"255\" – must have 4 octets\n- \"y.y.y.y\" – the only digit has allowed\n- \"255.0.0.y\" – the only digit has allowed\n- \"666.10.10.20\" – digit must between [0-255]\n- \"4444.11.11.11\" – digit must between [0-255]\n- \"33.3333.33.3\" – digit must between [0-255]\n- \"2001:0db8:85a3:0000:0000:8a2e:0370:7334\" (Ipv6)\n\n\n### IPv6 Rule\nThis form rule confirms that value is an IPv6 address.\n\n\u003e Passing IPv6 Rule\n- \"2001:0db8:85a3:0000:0000:8a2e:0370:7334\" (Ipv6)\n\n\u003e Failing IPv6 Rule\n- \"210.110\" – must have 4 octets\n- \"255\" – must have 4 octets\n- \"y.y.y.y\" – the only digit has allowed\n- \"255.0.0.y\" – the only digit has allowed\n- \"666.10.10.20\" – digit must between [0-255]\n- \"4444.11.11.11\" – digit must between [0-255]\n- \"33.3333.33.3\" – digit must between [0-255]\n- \"110.234.52.124\"\n- \"192.168.0.1\"\n- \"115.42.150.37\"\n\n\n### Json Rule\nThe given field value must be a Json String\n\n\u003e Passing Json Rule\n```js\nlet data = { content: JSON.stringify({ inspire: 'love' }) };\nlet rules = { content: 'json' };\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Json Rule\n```js\nlet data = { content: 'fasdf' }\nlet rules = { content: 'json' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n### Max Rule\nThe given field must not be more than the defined maximum limit\n\n\u003e Passing Max Limit Rule\n```js\nlet data = { password: 'secret' }\nlet rules = { password: 'max:10' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Max Limit Rule\n```js\nlet data = { password: 'secret'}\nlet rules = { password: 'max:4' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n### Min Rule\nThe given field must not be less than the defined minimum limit\n\n\u003e Passing Min Limit Rule\n```js\nlet data = { password: 'secret' }\nlet rules = { password: 'min:6' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Min Limit Rule\n```js\nlet data = { password: 'secret'}\nlet rules = { password: 'min:8' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\n### Not Regex Rule\nThe given field value must NOT match the regular expression pattern\n\n\u003e Passing Not Regex Rule\n```js\nlet data = { email: 'ex.-fn' };\nlet rules = { email: ['not_regex:/^.+@.+$/i'] };\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Not Regex Rule\n```js\n\n\nlet data = { email: 'example@gmail.com'}\nlet rules = { email: ['not_regex:/^.+@.+$/i'] }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\n### Not Within Rule\nThe given field must NOT be \"within\" the comma delimited list of items\n\n\u003e Passing Not Within Rule\n```js\nlet data = { language: 'PigLatin' }\nlet rules = { language: 'not_within:German,Spanish,English,Latin' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Not Within Rule\n```js\nlet data = { pencil: '2a'};\nlet rules = { pencil: 'not_within:notebook,pencil,2a,marker,sharpie,whiteboard' };\n\nform(data).rules(rules).validate().errors().any();\n```\n\n### Number Rule\nThe given field must be a Number (Strict Typed Check). See Numeric For Looser Type Checking\n\n\u003e Passing Number Rule\n```js\nlet data = { id: 15 };\nlet rules = { id: ['number'] };\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Number Rule\n```js\nlet data = { id: '15'}\nlet rules = { id: ['number'] }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n### Numeric Rule\nDetermine if a value is numeric, or is a string that can properly represent a numeric\n\n- Numerical value, not strict number check\n- Automatically attempts to cast value to numerical value.\n- Validates that field value an integer, decimal, or bigInt.\n\n\u003e Passing Numeric Rule\n```js\nlet data = { members: '25' }\nlet rules = { member: ['numeric'] }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Numeric Rule\n```js\nlet data = { members: 'yes' }\nlet rules = { member: ['numeric'] }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\n### Phone Rule\nThe given field value must be a phone number\n\n\u003e Passing Phone Rule\n```js\nlet data = { send_sms: ['555-555-5555'] }\nlet rules = { send_sms: ['phone'] }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Phone Rule\n```js\nlet data = { send_sms: '+(3) - 4 32'}\nlet rules = { send_sms: ['phone'] }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Phone Number Formats Within Testing Coverage\n- +61 1 2345 6789\n- +61 01 2345 6789\n- 01 2345 6789\n- 01-2345-6789\n- (01) 2345 6789\n- (01) 2345-6789\n- 5555555555\n- (555) 555 5555\n- 555 555 5555\n- +15555555555\n- 555-555-5555\n\n\u003e _(Any contributions welcome (vuejs-validators.js repo) for improving regex form patterns for current rules as well as adding new rules)_\n\n\n### Regex Rule\nThe given field value must match the regular expression pattern\n\n\u003e Passing Regex Rule\n```js\nlet data = { email: 'example@gmail.com' };\nlet rules = { email: ['regex:/^.+@.+$/i'] };\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Regex Rule\n```js\nlet data = { email: 'ex.-fn'}\nlet rules = { email: ['regex:/^.+@.+$/i'] }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\n### Required Rule\nValidates that a given field exists and its value is set\n\n\u003e Passing Required Rule\n```js\nlet data = { name: 'jules' };\nlet rules = { name: ['required'] };\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Required Rule\n```js\nlet data = { name: '' };\nlet rules = { name: ['required'] };\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\n### Same form Rule\nThe given field value is the same as another field value\n\n\u003e Passing Same Rule\n```js\nlet data = { password: 'secret', confirm_password: 'secret' }\nlet rules = { password: 'same:confirm_password' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Same Rule\n```js bash\nlet data = { password: 'asdfasdfasdf', confirm_password: 'secret' };\nlet rules = { password: 'same:confirm_password' };\n\nform(data).rules(rules).validate().errors().any();\n```\n\n### Starts With Rule\nThe field under form must start with one of the given values.\n\n\u003e Passing Starts With Rule\n```js\nlet data = { name: 'sammie' };\nlet rules = { name: 'starts_with:joe,sam,tom' };\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Starts With Rule\n```js\nlet data = { name: 5 };\nlet rules = { name: 'starts_with:sl,ie,asx' };\n\nform(data).rules(rules).validate().errors().any();\n\nform.setData({ name: 'azure' })\n    .setRules({ name: 'starts_with:joe,sam,tom'})\n    .validate()\n    .errors()\n    .any();\n```\n\n\n### String Rule\nThe given field value must be a String\n\n\u003e Passing String Rule\n```js\nlet data = { name: 'sammie' };\nlet rules = { name: 'string' };\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing String Rule\n```js\nlet data = { name: 54345  }\nlet rules = { name: 'string' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n### Url Rule\nThe given field value must be an http(s) url\n\n\u003e Passing Url Rule\n```js\nlet data = { link: 'https://cleancode.studio' };\nlet rules = { link: 'url' };\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Url Rule\n```js\nlet data = { link: 'httP/ope_type@.net'}\nlet rules = { link: 'url' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\n### Within Rule\nThe given field must be \"within\" the comma delimited list of items\n\n\u003e Passing Within Rule\n```js\nlet data = { name: 'Sam' }\nlet rules = { name: 'within:James,Boronica,Sam,Steve,Lenny' }\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\u003e Failing Within Rule\n```js\nlet data = { name: 'jake'};\nlet rules = { name: 'within:patricia,veronica,samuel,jeviah' };\n\nform(data).rules(rules).validate().errors().any();\n```\n\n\n## Form Error Messages Api\n\u003e form.errors() Methods\n- [any()](#any-errors)\n- [all()](#all-errors)\n- [list()](#list-errors)\n- [set(errors)](#set-errors)\n- [forget()](#forget-errors)\n- [has(field)](#has-error)\n- [get(field)](#get-error)\n- [list(field)](#list-error)\n- [add(field, message)](#add-error)\n- [set(field, messages)](#set-field-errors)\n- [forget(field)](#forget-field)\n- [getValidator()](#get-errors-validator)\n\n\n### Any Errors\n\u003e Determine if there are \"any\" errors (bool)\n```js\nlet data = { name: '' };\nlet rules = { name: 'required'};\nform(data).rules(rules).errors().any();\n```\n```\nOutput: true\n```\n\n\n### All Errors\n\u003e Retrieve all errors within the errors object\n\n```js\nlet data = { name: '', email: '' };\nlet rules = { name: 'required', email: 'email|required' };\n\nform(data).rules(rules).validate().errors().all();\n```\n```\nOutput:\n\n{\n    name: [\n        'name field is required'\n    ],\n    email: [\n        'email field must be an email address',\n        'email field is required'\n    ]\n}\n```\n\n\n\n### List Errors\n\u003e Retrieve all errors within the errors object\n```js\nlet data = { name: '', email: '' };\nlet rules = { name: 'required', email: 'email|required' };\n\nform(data).rules(rules).validate().errors().list();\n```\n```\nOutput:\n\n[\n    'name field is required',\n    'email field must be an email address',\n    'email field is required'\n]\n```\n\n\n\n### Set Errors\n\u003e Set all errors\n\n```js\nlet data = { name: '' };\nlet rules = { name: 'required' };\n\nform(data).rules(rules).validate();\n\nform.errors().list(); \n// Output: ['name is a required field']\n\nform.errors().set({ notice: ['set this random error message'] });\nform.errors().list()\n```\n```\nOutput: ['set this random error message']\n```\n\n\n### Forget Errors\n\u003e Forget errors and reset them to empty\n```js\nlet data = { name: '' };\nlet rules = { name: 'required' };\n\nform(data).rules(rules).validate().errors().list();\n// Output: ['Name is a required field']\n\nform.errors().forget();\nform.errors().list();\n```\n``` \nOutput: []\n```\n\n### Has Error\n\u003e Determine if a specific field has error messages\n\n```js\nlet data = { name: '', email: 'example@gmail.com' };\nlet rules = { name: 'required', email: 'email|required' };\nform(data).rules(rules).validate();\n\nform.errors().has('name');\nform.errors().has('email');\nform.errors().has('something_else');\n```\n```\nOutput:\nhas name: true\nhas email: false\nhas something_else: false\n```\n### Get Error\n\u003e Get _first_ error message for a specific field\n```js\nlet data = { name: '' };\nlet rules = { name: 'required|min:3'};\n\nform(data).rules(rules).validate().errors().get('name');\n```\n```\nOutput: \"Name is a required field\"\n```\n\n### List Error\n\u003e List errors for a specific field\n```js\nlet data = { name: '' };\nlet rules = { name: 'required|min:3'};\n\nform(data).rules(rules).validate().errors().list('name');\n```\n``` \nOutput: ['name is a required field', 'name must be longer than 3 characters']\n```\n\n### Add Error\n\u003e Add error message for a specific field\n```js\nlet data = { name: '' };\nlet rules = { name: 'required|min:3'};\n\nform(data).rules(rules).validate().add(\n    'name', 'four failures in a row. Two more failures before your locked out'\n);\n\nform.errors().list('name');\n```\n``` \nOutput: ['name is a required field', 'name must be longer than 3 characters', 'four failures in a row. Two more failures before your locked out']\n```\n\n\n### Set Error\n\u003e Set error messages for a specific field\n```js\nlet data = { name: '' };\nlet rules = { name: 'required' };\n\nform(data).rules(rules).validate().list('name');\n```\n``` \nOutput: ['name is a required field']\n```\n```js \nform.errors().set('name', ['random messages', 'set on', 'the name field']);\nform.errors().list('name');\n```\n```\nOutput: ['random messages', 'set on', 'the name field']\n```\n\n### Forget Error\n\u003e Forget error messages for a specific field\n```js\nlet data = { name: '' };\nlet rules = { name: 'required' };\n\nform(data).rules(rules).validate().list('name');\n```\n``` \nOutput: ['name is a required field']\n```\n```js \nform.errors().forget('name');\nform.errors().list('name');\n```\n```\nOutput: []\n``` \n\n---\n\n## Extending the Error Bag\n\n---\n\n---\n\n### Error Bag Macro \n\n---\nAdds custom method on form error bag instance\n\n```js \nlet example = form(data).rules(rules);\n\nlet example.errors().macro('count', function () {\n    return this.list().length;\n});\n\n\n// example.errors().count() === example.errors().list().length\n ```\n\n\n---\n\n### Error Bag ForceMacro\n\n---\nAllows you to overwrite pre-defined macro and over write core error message bag functions (Use With Caution)\n\n```js\nlet example = form({ name: '' }).rules({ name: 'required|min:3' }).validate();\n\nexample.errors().get('name'); // Outputs: \"Name is a required field\"\n\nexample.errors().forceMacro('get', function (field) {\n    if (this.has(field)) {\n        return this.list(field).join(', ') + '.';\n    }\n});\n\nexample.errors().get('name'); // Outputs: \"Name is a required field, name must have at least 3 characters.\"\n```  \n\n\n- [all](#all\n- [boolean](#boolean\n- [empty](#empty\n- [except](#except\n- [fill](#fill\n- [filled](#filled\n- [forceMacro](#forcemacro\n- [forget](#forget\n- [has](#has\n- [hasAny](#hasany\n- [input](#input\n- [keys](#keys\n- [macro](#macro\n- [make](#make\n- [missing](#missing\n- [only](#only\n- [set](#set\n- [toArray](#toarray\n- [wrap](#wrap\n\n#### `all()`\n\nThe all method returns the underlying input object represented by the form:\n\n```js\n\nform({ name: 'sarah', email: 'sarah@gmail.com' }).all();\n\n// { name: 'sarah', email: 'sarah@gmail.com' }\n\n```\n\n#### `boolean(property)`\n\nThe boolean method determines if the given field has a truthy or falsy values:\n\n#### Truthy values: true, \"true\", \"yes\", \"on\", \"1\", 1\n\n#### Falsy values: Everything else\n\n```js\n\nconst LoginForm = form({\n\n    name: '',\n\n    email: '',\n\n    terms: ''\n\n})\n\nLoginForm.terms = true\n\nLoginForm.boolean('terms') // true\n\nLoginForm.terms = 'true'\n\nLoginForm.boolean('terms') // true\n\nLoginForm.terms = 'yes'\n\nLoginForm.boolean('terms') // true\n\nLoginForm.terms = 'on'\n\nLoginForm.boolean('terms') // true\n\nLoginForm.terms = \"1\"\n\nLoginForm.boolean('terms') // true\n\nLoginForm.terms = 1\n\nLoginForm.boolean('terms') // true\n\n```\n\n\n#### `empty(one, two, three, ...)`\n\nThe empty method determines if the input property exists but the value is empty:\n\n```js\n\nconst ExampleForm = form({ id: '', name: 'sarah', email: 'sarah@gmail.com' });\n\nExampleForm.empty('name') // false\n\nExampleForm.empty('name', 'email') // false\n\nExampleForm.empty('id') // true\n\n```\n\n#### `except(one, two, three, ...)`\n\nThe except method grabs all of the inputs except the properties passed in:\n\n```js\n\nconst ExampleForm = form({ id: '', name: 'sarah', email: 'sarah@gmail.com' });\n\nExampleForm.except('id')\n\n/**\n\n * { name: 'sarah', email: 'sarah@gmail.com' }\n\n*/\n\nExampleForm.except('id', 'name')\n\n/**\n\n * { email: 'sarah@gmail.com' }\n\n */\n\n```\n\n[View source on GitHub](https://github.com/zhorton34/vuejs-form.js/blob/master/src/methods/except.js)\n\n#### `fill({ key: value, keyTwo: valueTwo, etc... })`\n\nThe fill method allows you to fill in new or empty values without overriding existing values:\n\n```js\n\nconst ExampleForm = form({ id: '', name: 'sarah', email: 'sarah@gmail.com' });\n\nExampleForm.fill({\n\n    id: 2,\n\n    name: 'tim',\n\n    email: 'tim@gmail.com'\n\n})\n\nExampleForm.all()\n\n// { id: 2, name: 'sarah', email: 'sarah@gmail.com' }\n\n```\n\n#### `filled(propertyOne, propertyTwo, etc...)`\n\nThe filled method determine if a value is filled (AKA not empty):\n\n```js\n\nconst ExampleForm = form({ id: '', name: 'sarah', email: 'sarah@gmail.com' });\n\nExampleForm.filled('id', 'name') // false\n\nExampleForm.filled('name', 'email') // true\n\n```\n\n#### `forceMacro(key, fn)`\n\nforceMacro can be used to extend form object and FORCIBLY OVERWRITE base form behavior (Use VERY cautiously and prefer macro over forceMacro)\n\n_NOTE: Use forceLocalMacro if you only want to extend a specific form instance instead of all form instances._ \n\n```js\n\nimport form from 'vuejs-form';\n\nform().forceMacro('all', function () {\n\n    return this.keys().reduce((list, field) =\u003e ({\n\n            ...list,  \n\n            [field]: { \n\n                name: field, \n\n                value: this.data[field],\n\n                errors: this.errors().list(field),\n\n            }\n\n        }), \n\n    {});\n\n})\n\nform({ name: 'sam' }).rules({ name: 'required' }).validate();\n\n```\n\n```\n\n# forceMacro implementation of form.all() Outputs\n\n{\n\n    name: {\n\n        value: 'sam',\n\n        name: 'name',\n\n        errors: ['Name field is required']\n\n    }\n\n}\n\n```\n\n[View source on GitHub](https://github.com/zhorton34/vuejs-form.js/blob/master/src/methods/forceMacro.js)\n\n#### `forget(propertyOne, propertyTwo, etc...)`\n\nThe forget method will remove or \"forget\" a key value pair from the form input data\n\n```js\n\nconst ExampleForm = form({ id: '', name: 'sarah', email: 'sarah@gmail.com' });\n\nExampleForm.forget('id', 'name')\n\nExampleForm.all() // { email: 'sarah@gmail.com' }\n\n```\n\n#### `has(propertyOne, propertyTwo, etc...)`\n\nThe has method will determine if a key exists within the form input data\n\n```js\n\nconst ExampleForm = form({ id: '', name: 'sarah', email: 'sarah@gmail.com' });\n\nExampleForm.has('id', 'name') // true\n\nExampleForm.has('something', 'id', 'name') // false\n\n```\n\n#### `hasAny(propertyOne, propertyTwo, etc...)`\n\nThe hasAny method will determine if a key has any of the given properties within the form input data\n\n```js\n\nconst ExampleForm = form({ id: '', name: 'sarah', email: 'sarah@gmail.com' });\n\nExampleForm.hasAny('id', 'name') // true\n\nExampleForm.hasAny('something', 'id', 'name') // true\n\n```\n\n#### `input(property, default = false)`\n\nThe input method will resolve a given input value or default to false. You can define a default as the second parameter\n\n```js\n\nconst ExampleForm = form({ id: '', name: 'sarah', email: 'sarah@gmail.com' });\n\nExampleForm.input('id') // false\n\nExampleForm.input('id', 1) // 1\n\nExampleForm.input('name', 'tim') // sarah\n\n```\n\n#### `keys()`\n\nThe keys method will resolve an array of the input keys\n\n```js\n\nconst ExampleForm = form({ id: '', name: 'sarah', email: 'sarah@gmail.com' });\n\nExampleForm.keys() // ['id', 'name', 'email']\n\n```\n\n\n#### `macro(key, fn)`\n\nThe macro method can be used to extend the forms base behavior with custom methods/functions\n\n_NOTE: Use localMacro if you only want to extend a specific form instance instead of all form instances._\n\n \n\n```js\n\nimport form from 'vuejs-form';\n\nform(data).macro('count', () =\u003e {\n\n    return this.keys().length;\n\n});\n\n// form.count() === form.keys().length\n\n```\n\n[View source on GitHub](https://github.com/zhorton34/vuejs-form.js/blob/master/src/methods/macro.js)\n\n#### `make({ ... })`\n\nThe make method will \"make\" a new form when used on the underlying class (With the proxy used on all forms)\n\n```js\n\nimport { VueForm } from 'vuejs-form'\n\nconst ExampleForm = VueForm.make({ id: '', name: 'sarah', email: 'sarah@gmail.com' })\n\nExampleForm.all() // { id: '', name: 'sarah', email: 'sarah@gmail.com' }\n\n```\n\n\n#### `missing(propertyOne, propertyTwo, ...)`\n\nThe missing method will determine if the form is missing the following properties\n\n```js\n\nconst ExampleForm = form({ id: '', name: 'sarah', email: 'sarah@gmail.com' })\n\nExampleForm.missing('id') // false\n\nExampleForm.missing('something') // true\n\nExampleForm.missing('name', 'email') // false\n\nExampleForm.missing('name', 'email', 'something') // true\n\n```\n\n\n#### `only(propertyOne, propertyTwo, ...)`\n\nThe only method will return an object of \"only\" the input properties you defined\n\n```js\n\nconst ExampleForm = form({ id: '', name: 'sarah', email: 'sarah@gmail.com' })\n\nExampleForm.only('name', 'email') // { name: 'sarah', email: 'sarah@gmail.com' }\n\nExampleForm.only('id', 'name') // { id: '', name: 'sarah' }\n\nExampleForm.only('id') // { id: '' }\n\n```\n\n\n#### `set({ key: value, keyTwo: valueTwo, etc... })`\n\nThe set method allows you to set new and override previous values:\n\n```js\n\nconst ExampleForm = form({ id: '', name: 'sarah', email: 'sarah@gmail.com' });\n\nExampleForm.set({\n\n    id: 2,\n\n    name: 'tim',\n\n    email: 'tim@gmail.com',\n\n    password: 'secret',\n\n})\n\nExampleForm.all()\n\n// { id: 2, name: 'tim', email: 'tim@gmail.com', password: 'secret' }\n\n```\n\n#### `toArray()`\n\nThe toArray method transforms the input into an array of key value pair objects:\n\n```js\n\nconst ExampleForm = form({ id: '', name: 'sarah', email: 'sarah@gmail.com' });\n\nExampleForm.toArray()\n\n/**\n\n    [\n\n        { key: 'id', value: '' },\n\n        { key: 'name', value: 'sarah' },\n\n        { key: 'email', value: 'sarah@gmail.com' }\n\n    ]\n\n*/\n\n```\n\n#### `wrap(key)`\n\nThe wrap method allows you to wrap the input within a given object key:\n\n```js\n\nconst ExampleForm = form({ id: '', name: 'sarah', email: 'sarah@gmail.com' });\n\nExampleForm.wrap('data')\n\n/**\n\n  {\n\n    data: {\n\n        id: '',\n\n        name: 'sarah',\n\n        email: 'sarah@gmail.com'\n\n    }\n\n  }\n\n*/\n\n```\n\n---\n\n## Extend Api\n\n---\n\nExtend and append functionality to just about every single major service this package provides\n\n- [Extend Form Using Macros](#extend-form-using-macros)\n- [Extend Validator Using Macros](#extend-validator-using-macros)\n- [Extend Error Messages Bag Using Macros](#extend-error-messages-api)\n- [Add Custom Error Messages](#extending-custom-error-messages)\n- [Create Custom Validation Rule](#extending-custom-rules---single-rule)\n- [Create Custom Validation Rules](#extending-custom-rules---multiple-rules)\n- [Extend Into Multi Step Form Example](#extend-form-into-multi-step-form-not-tested-but-good-base-to-provide-some-ideas)\n\n#### Extend Form Using Macros\n```javascript\nconst form = require('vuejs-form');\n\nform().macro('shortcut', () =\u003e {\n    return this.validate().errors().list();\n});  \n\nlet example = form({ name: '' }).rules({ name: 'required' });\n\nexample.shortcut();\n// Output: ['Name is a required field'];\n```\n\n#### Extend Validator Using Macros\n```javascript\nconst { form, validator } = require('vuejs-form');\n\nvalidator().macro('translate', ({ dictionary, locale }) =\u003e {\n    if (!Object.keys(dictionary).includes(locale)) {\n    \tconsole.warn(`Translation dictionary does not include passed ${locale}`);\n\n        return this;\n    } \n    \n    const language = Object.keys(this.messages);\n    const dictionary_words = key =\u003e Object.keys(dictionary[locale]).includes(key);\n    language.filter(dictionary_words).forEach(key =\u003e { this.messages[key] = dictionary[`${locale}.${key}`] });\n\n    return this;\n});\n\nlet example = form({ name: '' }).rules({ name: 'required' });\n\nlet locale = 'ru';\nlet dictionary = { ru: { email: \"Эл.почта\" } };\n\nexample.validator().translate({ locale, dictionary });\n```\n\n\n---\n\n#### Extending Error Messages Api\n\n---\n\n---\n\n##### Error Bag Macro\n\n---\nAdds custom method on form error bag instance\n\n```js \nlet example = form(data).rules(rules);\n\nlet example.errors().macro('count', function () {\n    return this.list().length;\n});\n\n\n// example.errors().count() === example.errors().list().length\n ```\n\n\n---\n\n##### Error Bag ForceMacro\n\n---\nAllows you to overwrite pre-defined macro and over write core error message bag functions (Use With Caution)\n\n```js\nlet example = form({ name: '' }).rules({ name: 'required|min:3' }).validate();\n\nexample.errors().get('name'); // Outputs: \"Name is a required field\"\n\nexample.errors().forceMacro('get', function (field) {\n    if (this.has(field)) {\n        return this.list(field).join(', ') + '.';\n    }\n});\n\nexample.errors().get('name'); // Outputs: \"Name is a required field, name must have at least 3 characters.\"\n```  \n\n#### Extending: Custom Error Messages\n- This has nothing to do with the error messages Api\n- These are the literal string output a rule message will display when it fails\n- Here we'll customize error messages for specific rules on any given field\n\n- Globally, each rule provides a default error message\n- Easily override rule's default error message\n- Simply pass 'messages' to our validator\n- Only override messages you want to\n\n```javascript\nlet data = { name: '', email: '' };\n\nlet rules = {\n    name: ['min:3', 'max:12', 'string', 'required'],\n    email: ['email', 'required']\n};\n\nlet customMessages = {\n    'name.min': 'Whoops! :attribute is less than :min characters',\n    'name.required': 'Wha oh, doesnt look like there any value for your :attribute field',\n\n    'email.email': 'Really? Email is called Email...it has to be an email...',\n};\n\nform(data).rules(rules).messages(customMessages).validate().errors().all();\n```\n\n#### Extending: Custom Rules\n\u003e Add Your Own Validation Rules\n\n- Easily add, or override, validation rules\n- Add a group of rules at a time\n- Add a single rule add a time\n\n#### Extending: Custom Rules - Single Rule\n\u003e form().validator().extend(rule_name, [message, rule])`\n```js\nlet example = form({ name: 'timmy' }).rules({ name: 'uppercase' });\n\nexample.validator().extend('uppercase', [\n    ':attribute must be uppercase',\n    ({ value, validator, parameters }) =\u003e value === value.toUpperCase(),\n]);\n\n// true\nexample.validate().errors().has('name');\n\n// \"Name must be uppercase\"\nexample.errors().get('name');\n```\n\n#### Extending: Custom Rules - multiple rules\n\u003e `form.validator().extend({ first: [message, rule], second: [message, rule], etc... })`\n```js\nlet example = form({ name: '' }).rules({ name: ['required_with:last_name', 'required' ] });\n\nexample.validator().extend({\n    uppercase: [\n       ':attribute must be uppercase',\n        ({ value }) =\u003e value === value.toUpperCase(),\n    ],\n    not_uppercase: [\n        ':attribute must not be uppercase',\n        ({ value }) =\u003e value !== value.toUpperCase()\n    ],\n    required_without: [\n        ':attribute is only required when form is missing :required_without field',\n        ({ validator, parameters }) =\u003e !Object.keys(validator.data).includes(parameters[0])\n    ],\n    required_with: [\n        ':attribute is required with the :required_with field',\n        ({ validator, parameters }) =\u003e Object.keys(validator.data).includes(parameters[0])\n    ],\n});\n```\n\n#### Extend Form Into Multi Step Form (Not tested, but good base to provide some ideas)\n- Not actually tested outside of these docs, but solid starting point\n\n```html\n\u003ctemplate\u003e\n    \u003cdiv class=\"form-container\"\u003e\n        \u003csmall\u003e\n            Step {{ multi.steps().currentStep }} of {{ multi.steps().count() }}\n        \u003c/small\u003e\n        \n        \u003c!-- Pass form data as props, via vuex, emit event on any data change from all form field children, or if your safe wit it simply reference this.$parent.multi.steps().current from the child field. If you do so, don't plan on using the child component outside of multi-step forms. this.$parent is traditionally bad practice --\u003e\n        \u003ccomponent :is=\"multi.steps().current().getComponent()\"\u003e\u003c/component\u003e\n        \n        \u003cbutton class=\"btn-default\" v-if=\"multi.steps().hasPrev()\" @click=\"multi.steps().prev()\"\u003e\n            Prev\n        \u003c/button\u003e\n\n        \u003cbutton class=\"btn-primary\" :disabled='multi.steps().current().errors().any()' v-if=\"multi.steps().hasNext()\" @click=\"multi.steps().next()\"\u003e\n            Next    \n        \u003c/button\u003e\n        \n        \u003cbutton class=\"btn-success\" :disabled='multi.steps().current().errors().any()' v-if=\"multi.steps().isLast()\" @click=\"submit\"\u003e\n            Done\n        \u003c/button\u003e\n    \u003c/div\u003e\n\u003c/template\u003e\n```\n\n```javascript\n\nconst MultiStep = function (form) {\n    this.sections = {};\n\tthis.currentStep = 0;\n\n\tthis.parent = function () {\n\t\treturn form;\n\t};\n    \n    this.current = function () {\n        if (this.has(this.currentStep)) {\n            return this.get(this.currentStep);\n        } else {\n            console.error(\"No current step found\");\n        }\n    };\n    \n    this.currentComponent = function () {\n        return this.current().component_is\n    };\n    this.count = function () {\n        return this.list().length;\n    };\n\n    this.travel = function (to) {\n        if (this.has(to)) {\n            this.currentStep = to;\n            \n            return this.current();\n        } else {\n            return console.error(`form step ${to} not found`);\n        }\n    };\n    \n    this.prev = function () {\n        if (!this.isFirst()) {\n            this.currentStep = this.currentStep - 1;\n    \n            return this.current();\n        } else {\n            console.error('already on the very first step')\n        }\n    };\n\n    \n    this.next = function () {\n        if (!this.isLast()) {\n            this.currentStep = this.currentStep + 1;\n        \n            return this.current();\n        } else {\n            console.log('last step')\n        }\n    };\n\n    this.hasPrev = function () {\n        return this.has(this.currentStep + 1);\n    };\n    \n    this.hasCurrent = function () {\n        return this.has(this.currentStep);\n    };\n    \n    this.isFirst = function () {\n        return this.hasCurrent() \u0026\u0026 !this.hasPrev()\n    };\n    \n    this.isLast = function () {\n        return this.hasCurrent() \u0026\u0026 !this.hasNext();\n    };\n\n    this.hasNext = function () {\n        return this.has(this.currentStep + 1)\n    };\n\n\tthis.any = function () {\n        const isEmpty = value =\u003e ([\n            value === null || value === '',\n            Array.isArray(value) \u0026\u0026 value.length === 0,\n            typeof value === 'object' \u0026\u0026 Object.keys(value).length === 0\n        ].includes(true));\n        \t\n\t\treturn !isEmpty(this.list());\n\t};\n\n\tthis.has = function (group) {\n\t\treturn Object.keys(this.sections).includes(group)\n\t\t\t\u0026\u0026 this.sections[group].length \u003e 0\n\t};\n\n\tthis.all = function () {\n\t\treturn this.sections;\n\t};\n\n\tthis.list = function (group = false) {\n\t\treturn group\n\t\t\t? this.sections[group]\n\t\t\t: Object.keys(this.sections)\n\t\t\t\t.map(group =\u003e this.sections[group])\n\t\t\t\t.reduce((list, groups) =\u003e [ ...list,  ...groups ], []);\n\t};\n\n\tthis.get = function (group) {\n\t\tif (this.has(group)) {\n\t\t\treturn this.sections[group][0];\n\t\t}\n\t};\n\n\tthis.add = function(group, item) {\n\t\tthis.sections[group] = Array.isArray(this.sections[group])\n\t\t\t? this.sections[group]\n\t\t\t: [];\n\n\t\tthis.sections[group].push(item);\n\n        return this;\n\t};\n\n\tthis.set = function (group, items = []) {\n\t\tif (typeof items === 'object') {\n\t\t\tthis.sections = items;\n\t\t} else {\n\t\t\tthis.sections[group] = items;\n\t\t}\n\t};\n\n\tthis.forget = function (group) {\n\t\tif (typeof group === 'undefined') {\n\t\t\tthis.sections = {};\n\t\t} else {\n\t\t\tthis.sections[group] = [];\n\t\t}\n\t};\n};\n\n\nconst steppable = function (form = {}) {\n\treturn new MultiStep(validator);\n};\n\nform().macro('multiple', () =\u003e {\n    this.steppables = steppable(this);\n    \n    this.steps = function () {\n        return this.steppables;\n    };\n    \n    this.first = function () {\n        return this.steps().get('0')\n    }\n    \n    this.last = function () {\n        return this.steps().list(this.steps().count() - 1);\n    };\n    \n    this.current = function () {\n        return this.steps().current();\n    };\n\n    \n    return this;\n});\n\nform().multiple().steps();\n\n\n/** Use macro to extend form and append vue component instance to each form step **/\nform().macro('hasComponent', () =\u003e typeof this.component_is !== 'undefined');\nform().macro('getComponent', () =\u003e {\n     this.hasComponent() ? this.component_is : `\u003ctemplate\u003e\u003cdiv\u003eNo Component Registered On This Form Instance\u003c/div\u003e\u003c/template\u003e`\n});\n\nform().macro('is', (vue_instance) =\u003e {\n    this.component_is = vue_instance;\n\n    return this;\n});\n\nform().multiple().steps();\n\nconst { name_fields, password_fields, final_step } = require('./components/forms/steps/index.js');\n\nlet multi = form({}).multiple();\n\nmulti.steps().add(0, \n    form({ \n        last_name: '', \n        first_name: '' \n    })\n    .rules({\n        last_name: ['required', 'min:3', 'string', 'different:first_name'],\n        first_name: ['required', 'min:3', 'string', 'different:last_name']\n    })\n    .messages({\n        'last_name.required': 'Last name is required',\n        'last_name.min': 'Last name may not be less than :min characters',\n        'last_name.different': 'Last Name must be different than first name',\n        'last_name.string': 'Last Name must be a string',\n        'first_name.required': 'First name is required',\n        'first_name.min': 'First name may not be less than :min characters',\n        'first_name.different': 'Last Name must be different than last name',\n        'first_name.string': 'First name must be of the string type'\n    })\n    .is(name_fields)\n);\n\nmulti.steps().add(1,\n    form({ \n        password: '',\n        password_confirmation: '',\n    })\n    .rules({ \n        password: ['required', 'min:5', 'string', 'confirmed'],\n    })\n    .is(password_fields)\n);\n\nmulti.steps().add(2,\n    form({ terms_of_service: '' })\n    .rules({ terms_of_service: 'accepted|required' })\n    .messages({\n        'terms_of_service.accepted': \"Must accept terms of service before moving on\",\n        'terms_of_service.required': \"Must accept terms of service before submitting form\",\n    })\n    .is(final_step)\n);\n\n\nexport default {\n    name: 'multi-step-form',\n    data: () =\u003e ({ multi }),\n\n    methods: {\n        submit() {\n            let data = this.multi.steps().list().reduce((data, step) =\u003e ({ ...data, ...step.all() }), {});\n        \n            console.log('all data: ', form(data).all());\n        }\n    }\n};\n```\n\n\n## Macros\n \n- [Overview](#macros-overview)\n- [Macros](#extend-apis-via-macros)\n- [Local Macros](#extend-instances-via-local-macros)\n- [Force Macros](#overwrite-a-given-apis-core-via-force-macros)\n- [Force Local Macros](#overwrite-a-given-instances-core-via-force-local-macros)\n- [Macro Capable Apis List](#macro-capable-apis-list) \n\n### Macros Overview\n- Macros Are The Primary Way This Package And All Major Apis Are Extendable\n- One of this packages primary goals is to be unbiased, but provide _extreme_ extendability\n- Macros, and specifically four types of macros, are the primary way we are able to obtain this goal\n- Macros, in concept are extremely simple. \n- They simply add functions, extending behavior\n- Macros can accept arguments\n- Macros have access to `this` within the callback you are registering\n- There are four types of macros. \n- localMacro(name, fn) - extend instance with custom function (only the specific ) \n**Simplest Example** \n```\nform().hello(); // undefined\n\nform().macro('hello', function () {\n   return 'world';\n});\n\nform().hello(); // 'world'\n```\n\n### Extend Apis Via Macros\n`macro(name, fn)` \n- extend api with function \n- instance gains functions and constructor prototype gain function \n- applied to all new instances\n- can not overwrite core functions\n- can not overwrite pre-defined macros\n- can not be applied on more than a single instance (Technically you can try, it just won't actually do anything the methods already added)\n\n**Example: macro()**\nSimplify the validation process using a \"completed\" method wrapper\n \n```js\nform().macro('completed', function () {\n    this.validate();\n\n    return this.errors().any() === false;\n});\n\nform({ name: '' }).rules({ name: 'required' }).completed(); // false\nform({ name: 'samuel' }).rules({ name: 'required' }).completed(); // true\n```\n\n### Extend Instances Via LocalMacros\n`localMacro(name, fn)` \n**Example:** See multi-step form example provided for `forceLocalMacro` example. It provides a powerful example of possible ways to combine local and forceLocal macros.\n- extend instance with function\n- instance gains function\n- NOT applied to all new instances\n- can not overwrite core instances\n- can not overwrite pre-defined macros\n- can be applied on more than a single instance, but not automatically inherited globally\n**Example: localMacro**\n```js\n```\n### Overwrite A Given Apis Core Via Force Macros\n`forceMacro(name, fn)`\n- overwrite core api or existing macros \n- instance and constructor prototypes apply function \n- applies on all instances\n- can overwrite core functions\n- can overwrite pre-defined macros\n_NOTE: This is a very powerful function, use caution and when overriding core behavior understand things depend on other things under the hood. Only use this type of macro if no other macro solves your needs_\n\n**Force Macro Example**\n\u003e Overwrite Error Message Apis Get Method To Get A Comma List Of Messages Instead Of The First Message \n```js\nlet example = form({ name: '' }).rules({ name: 'required|min:3' }).validate();\n\nexample.errors().get('name'); // 'Name field is required'\n\nexample.errors().forceMacro('get', function (field) {\n    if (this.has(field)) {\n        return this.list(field).join(', ');\n    }\n});\n\nexample.errors().get('name'); // 'Name field is required, Name field must be more than 3 characters'\n```\n\n### Overwrite A Given Instances Core Via Force Local Macros\n`forceLocalMacro(name, fn)`\n- overwrite instances core behavior or existing macros \n- instance applies function\n- not applied by all instances, only on single instance \n- can overwrite core functions\n- can overwrite pre-defined macros\n_NOTE: Not quite as dangerous as forceMacro (it's only applied on one instance instead of globally across the api), it is still powerful and should be used only if localMacro doesn't solve your needs_\n\n**Create A Parent Form With Multiple Child Forms**\n_Example uses localMacro \u0026 forceLocalMacro (Advanced example)_\n\n```js\n\nlet MultiStepForm = form();\n\nMultiStepForm.localMacro('register', function (children = []) {\n    this.current = 0;\n    const $parent = this;\n\n    // Set local macros on each one of the child forms \n    this.children = children.map(child =\u003e {\n        // 1. localMacro: parent() method references parent form will all steps\n        child.localMacro('parent', () =\u003e $parent);\n        \n        // 2. forceLocalMacro: override validate() method to add in a step where child validate method populates parent() errors bag\n        //    Below we'll override the parent validate() method using a forceLocalMacro as well to two way bind this setup\n        child.forceLocalMacro('validate', function () {\n            const childForm = this;\n            childForm.validator().validate();\n            \n            childForm.parent().errors().set({\n                ...childForm.parent().errors().all(),\n                ...childForm.errors().all(),\n            });\n            \n            return this;\n        })\n    });\n    \n    /** Add helper methods for managing the multi-step form process **/\n    this.step = () =\u003e this.steps(this.current); \n    this.steps = index =\u003e index !== 'undefined' \u0026\u0026 this.hasStep(index) ? this.children(index) : this.children;\n    this.hasStep = index =\u003e typeof this.children[index] !== 'undefined';\n\n    this.prevStep = () =\u003e { this.current = this.current - 1; };\n    this.stepNumber = () =\u003e this.current + 1;\n    this.stepsCount = () =\u003e this.steps().length ;\n\n    this.hasPrevStep = () =\u003e this.hasStep(this.current - 1);\n    this.hasNextStep = () =\u003e this.hasStep(this.current + 1);\n    this.isLastStep = () =\u003e this.step() === this.steps(this.stepCount());\n    this.isFirstStep = () =\u003e this.step() === this.steps(0);\n\n    this.completedStepsCount = () =\u003e this.stepNumber();\n    this.remainingStepsCount = () =\u003e this.stepsCount() - this.stepNumber();\n    this.percentageCompleted = () =\u003e (this.completedStepsCount() / 100) * this.stepsCount();\n    this.percentageRemaining = () =\u003e (this.remainingStepsCount() / 100) * this.stepsCount();\n    this.next = () =\u003e {\n        if (this.hasNextStep()) this.current = this.current + 1;        \n    };\n    this.prev = () =\u003e {\n        if (this.hasPrevStep()) this.current = this.current - 1;\n    };\n    this.to = index =\u003e {\n        if (this.hasStep(index)) this.current = index;\n    }\n\n    return this;\n});\n\n/** forceLocalMacro to overwrite default all method on MultiStepForm ~ aggregating all child form data **/\nMultiStepForm.forceLocalMacro('all', function () {\n    return this.children.reduce((data, child) =\u003e ({ \n            ...data,\n            ...child\n        }), \n    {});\n});\n\n/** forceLocalMacro to overwrite default validate method on MultiStepForm ~ setting all error messages **/\nMultiStepForm.forceLocalMacro('validate', function () {    \n    this.errors().set(\n        this.children.reduce((errors, child) =\u003e ({\n                ...errors,\n                ...child.validate().errors().all()\n            }),\n        {})\n    );\n\n    return this;\n});\n\nMultiStepForm.register([\n    form({ first_name: '', last_name: '' }).rules({ first_name: 'required', last_name: 'required' }),\n    form({ email: '', phone_number: '' }).rules({ email: 'required|email', phone: 'required|phone' }),\n    form({ password: null, password_confirmation: '' }).rules({ password: 'required|min:7|confirmed|string '}),\n    form({ terms_of_services: null }).rules({ terms_of_services: 'required|accepted' })\n]);\n\nMultiStepForm.validate().errors().list();\n```\n\n```\nOutput:\n[\n    'First name is a required field',\n    'Last name is a required field',\n    'Email is a required field', \n    'Email must be an email',\n    'Phone number is a required field', \n    'Phone number must be a valid phone number',\n    'Password is a required field',\n    'Password must be at least 7 characters',\n    'Password must have the same value as the password confirmation field',\n    'Password must be a string',\n    'Terms Of Service is a required field',\n    'Terms Of Service has not been accepted, please accept to continue',\n]\n```\n### Macro Capable Api List\n- [Form Api Macros](#form-api-macros)\n- [Validator Api Macros](#validator-api-macros)\n- [Error Message Api Macros](#error-message-api-macros)\n\n#### Form Api Macros \n- form().macro(name, fn)\n- form().localMacro(name, fn)\n- form().forceMacro(name, fn)\n- form().forceLocalMacro(name, fn)\n  \n#### Validator Api Macros\n- form().validator().macro(name, fn)\n- form().validator().localMacro(name, fn)\n- form().validator().forceMacro(name, fn)\n- form().validator().forceLocalMacro(name, fn)\n\n#### Error Message Api Macros\n- form().errors().macro(name, fn)\n- form().errors().localMacro(name, fn)\n- form().errors().forceMacro(name, fn)\n- form().errors().forceLocalMacro(name, fn)\n\n\n---\n\n## Utilization\n\n---\n\n```js\nimport form from 'vuejs-form'\n\nconst LoginForm = form({\n    name: '',\n    email: '',\n    password: '',\n})\n\nLoginForm.name // ''\nLoginForm.name = 'sarah'\nLoginForm.name // 'sarah'\n\nform({\n    name: '',\n    email: '',\n    password: '',\n}).all() // { name: 'sarah', email: '', password: '' }\nform({\n    name: '',\n    email: '',\n    password: '',\n}).has('email', 'password') // true\nform({\n    name: '',\n    email: '',\n    password: '',\n}).has('email', 'something') // false\nform({\n    name: '',\n    email: '',\n    password: '',\n}).hasAny('email', 'something') // true\nform({\n    name: '',\n    email: '',\n    password: '',\n}).empty('email') // true\nform({\n    name: '',\n    email: '',\n    password: '',\n}).filled('email') // false\nform({\n    name: '',\n    email: '',\n    password: '',\n}).filled('name') // true\nform({\n    name: '',\n    email: '',\n    password: '',\n}).boolean('email') // false\nform({\n    name: '',\n    email: '',\n    password: '',\n}).only('email', 'name') // { email: '', name: '', }\nform({\n    name: '',\n    email: '',\n    password: '',\n}).except('password') // { email: '', name: '' }\nform({\n    name: '',\n    email: '',\n    password: '',\n}).input('password') // ''\nform({\n    name: '',\n    email: '',\n    password: '',\n}).input('email', 'example@gmail.com') // 'example@gmail.com'\n\nLoginForm.fill({\n    name: 'tim',\n    email: 'tim@gmail.com',\n    password: 'secret'\n})\n\nLoginForm.all() // { name: 'sarah', email: 'tim@gmail.com', password: 'secret' }\n\nLoginForm.set({\n    name: 'jamie',\n    email: 'jamie@gmail.com',\n    password: 'password'\n})\n\nLoginForm.all() // { name: 'jamie', email: 'tim@gmail.com', password: 'secret' }\n\nLoginForm.keys() // ['name', 'email', 'password']\n\nLoginForm.missing('verified') // true\nLoginForm.missing('email') // false\n\nLoginForm.toArray()\n/**\n [\n    { key: 'name', value: 'jamie' },\n    { key: 'email', value: 'tim@gmail.com' },\n    { key: 'password', value: 'secret' }\n ]\n*/\n\nLoginForm.wrap('data')\n/**\n{\n    data: {\n        name: 'jamie',\n        email: 'tim@gmail.com',\n        password: 'secret'\n    }\n}\n*/\n\nLoginForm.forget('password', 'email')\nLoginForm.all() // { name: 'jamie' }\n\n/**\n * When dealing with HTML elements like checkboxes, your application may receive \"truthy\" values that are actually strings. For example, \"true\" or \"on\". For convenience, you may use the boolean method to retrieve these values as booleans. The boolean method returns true for 1, \"1\", true, \"true\", \"on\", and \"yes\". All other values will return false:\n *   Boolean checks for\n*/\nLoginForm.boolean('name') // false\n\n\nLoginForm.terms = true\nLoginForm.boolean('terms') // true\nLoginForm.terms = 'true'\nLoginForm.boolean('terms') // true\nLoginForm.terms = 'yes'\nLoginForm.boolean('terms') // true\nLoginForm.terms = 'on'\nLoginForm.boolean('terms') // true\nLoginForm.terms = \"1\"\nLoginForm.boolean('terms') // true\nLoginForm.terms = 1\nLoginForm.boolean('terms') // true\n\n/** Anything else will return false Ex: */\nLoginForm.terms = 'asdfsdf'\nLoginForm.boolean('terms') // false\n```\n\n#### Extend Form Functionality\n```js\nimport form from 'vuejs-form'\n\nform().macro('count', () =\u003e {\n    return this.keys().length\n})\n\nform().macro('mapInto', into =\u003e {\n    // NOTICE: this.data is where the input object is actually stored\n\n    this.data = Object.entries(this.data).reduce((input, [key, value]) =\u003e ({\n            ...input,\n            ...into(key, value)\n        }),\n    {});\n\n    return this\n})\n\n\n\nconst extendedForm = form({\n    email: 'example@gmail',\n    password: 'secret',\n})\n\nform().macro((key, value) =\u003e ({ [key]: value.split('@') })).all()\n/**\n * { email: ['example', 'gmail'], password: 'secret' }\n */\n```\n\n\n\n\n\n\n---\n\n## Contribute\n\n---\n\nPRs are welcomed to this project.\nIf you want to improve the vuejs-form library, add\nfunctionality or improve the docs please feel free to submit a PR.\n\n\n---\n\n## Security Vulnerabilities\n\n---\n\nIf you discover a security vulnerability within Clean Code Studio Packages Or Specifically within vuejs-form, please\nsend an e-mail to Zachary Horton via zak@cleancode.studio. All security vulnerabilities will be promptly addressed.\n\n\n---\n\n## Change Log\n\n---\n- [Release 1.3.0 (Minor)](#release-130)\n- [Release 1.2.9 (Minor)](#release-129)\n- [Release 1.2.8 (Minor)](#release-128)\n- [Release 1.2.7 (Minor)](#release-127)\n- [Release 1.2.6 (Minor)](#release-126)\n- [Release 1.2.5 (Minor)](#release-125)\n- [Release 1.2.4 (Minor)](#release-124)\n- [Release 1.2.3 (Minor)](#release-123)\n- [Release 1.2.2 (Minor)](#release-122)\n- [Release 1.2.1 (Minor)](#release-121)\n- [Release 1.2.0 (Major)](#release-120)\n- [Release 1.1.1](#release-111)\n- [Release 1.1.0](#release-110)\n\n---\n\n### Release 1.3.0\n\n---\n- Fixed [first keypress not working bug](https://github.com/zhorton34/vuejs-form/issues/20)\n\n---\n\n---\n\n### Release 1.2.9\n\n---\n- Removed unused documentation assets\n\n---\n\n### Release 1.2.8\n\n---\n- date validation rule\n- date equals validation rule\n- before (date) validation rule\n- before_or_equal (date) validation rule\n- after (date) validation rule\n- after_or_equal (date) validation rule\n- less_than (numeric) validation rule\n- greater_than (numeric) validation rule\n- lte (less than or equal numeric) validation rule\n- gte (greater than or equal numeric) validation rule\n\n\n---\n\n### Release 1.2.7\n\n---\n- overwrite method outdated in place of forceMacro \n- macro method refactored, in depth testing and documentation\n- localMacro method created, in depth testing, and documentation\n- forceMacro method created, in depth testing, and documentation\n- forceLocalMacro method created, in depth testing, and documentation\n- Form Api is macro capable\n- Validator Api is macro capable\n- Error Messages Api is macro capable\n- Macro capabilities documentation for each macro type\n\n---\n\n### Release 1.2.6\n\n---\n\n- Beautified Docs A Bit\n- Vuejs Validations Ref Updated\n- MessageBag Added to Package Exports\n- MessageBagFactory Added to Package Exports\n- Error Messages Api Documentation Readme Updated\n\n---\n\n### Release 1.2.5\n\n---\n\n- Updated Cdn Documented Link Examples To Reference Latest Instead Of Specific Version \n\n\n---\n\n### Release 1.2.4\n\n---\n\n- Updated Purpose.md Documentation To Us Image Notepad Message \n\n\n---\n\n### Release 1.2.3\n\n---\n\n- Updated Change Log Release Link References\n- Updated Purpose.md Documentation To Us Image Notepad Message \n\n\n---\n\n### Release 1.2.2\n\n---\n\n- Updated Document Headers\n- Removed api.md section of Documentation\n- Removed bloated docs from setup.md\n- Added cdn installation and npm installation examples\n\n---\n\n### Release 1.2.1\n\n---\n\n- Updated Documentation To Start With \"Purpose\" Of Package\n- Removed Documentation Content From Header.md\n- Caught Change Log Up\n\n---\n\n### Release 1.2.0\n\n---\n\n- Documentation Updated\n- First Official Stable Release\n- Semantic Versioning Officially Supported\n\n \n\n---\n\n### Release 1.1.1\n\n---\n\n- CDN Setup\n- CDN Documentation Added\n- Added markdown.js for internal markup creation\n- Added Security Vulnerabilities Documentation\n- Added Versioning To Documentation\n- Added Code Of Conduct To Documentation\n- Extensive Documentation\n- Security Vulnerabilities Docs\n- Code Of Conduct Docs\n- Markdown Support Class\n- highlight.md \n- Versioning implementation documented\n\n\n\n---\n\n### Release 1.1.0\n\n---\n\n- \"form.getErrors()\" replaced with \"form.errors()\"\n- \"form.getValidator()\" replaced with \"form.validator()\"\n- \"vuejs-validators\" setup as dev dependency\n- \"ValidatableForm\" Export ~ (Ex: const { ValidatableForm } = require('vuejs-form'))\n- Default import is ValidatableForm (Ex: import form from 'vuejs-form' has validator || import { form } from 'vuejs-form' does not have validator)\n\n\n\n---\n\n## Versioning\n\n---\n\n\u003e Vuejs-Form Will Implement Semantic Versioning\n\u003e \n\u003e Starting (Friday, May 15, 2020)\n\n|Code Status|Stage|Rule|Example Version|\n|---|---|---|---|\n|First release|New Product|Start with 1.0.0|1.0.0|\n|Backward compatible bug fixes|Patch Release|Increment the third digit|1.0.1|\n|Backward compatible new features|Minor Release|Increment the middle digit and reset last digit to zero|1.1.0|\n|Changes that break backward compatibility|Major Release|Increment the first digit and reset middle and last digits to zero|2.0.0|\n\n- [Learn More About Semantic Versioning](https://docs.npmjs.com/about-semantic-versioning)\n\n\n---\n\n## License\n\n---\n\nMIT © [Zachary Horton (Clean Code Studio)](https://www.youtube.com/c/cleancodestudio)\n[Clean Code Studio ~ Clean Code Clean Life ~ Simplify](https://cleancode.studio)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzhorton34%2Fvuejs-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzhorton34%2Fvuejs-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzhorton34%2Fvuejs-form/lists"}