{"id":18368770,"url":"https://github.com/greena13/react-joi-validation","last_synced_at":"2025-04-06T17:31:52.596Z","repository":{"id":66163795,"uuid":"78231080","full_name":"greena13/react-joi-validation","owner":"greena13","description":"Extremely flexible validation using Joi and React","archived":false,"fork":false,"pushed_at":"2019-04-14T16:14:10.000Z","size":144,"stargazers_count":35,"open_issues_count":3,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-02T16:49:57.632Z","etag":null,"topics":["joi-validation","joy","react","react-native","validation"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/greena13.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-01-06T19:01:48.000Z","updated_at":"2022-09-06T05:06:04.000Z","dependencies_parsed_at":null,"dependency_job_id":"f49a7435-3e7b-483b-b967-88dfb8ed81e7","html_url":"https://github.com/greena13/react-joi-validation","commit_stats":{"total_commits":73,"total_committers":2,"mean_commits":36.5,"dds":"0.013698630136986356","last_synced_commit":"b3fb01d73d243e0216a470ccb8acd7d3cb1b91cd"},"previous_names":[],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greena13%2Freact-joi-validation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greena13%2Freact-joi-validation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greena13%2Freact-joi-validation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/greena13%2Freact-joi-validation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/greena13","download_url":"https://codeload.github.com/greena13/react-joi-validation/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247522428,"owners_count":20952546,"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":["joi-validation","joy","react","react-native","validation"],"created_at":"2024-11-05T23:27:22.851Z","updated_at":"2025-04-06T17:31:52.124Z","avatar_url":"https://github.com/greena13.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://svgshare.com/i/CRy.svg\" width=\"200px\" /\u003e\u003cbr/\u003e\n  \u003ch2 align=\"center\"\u003ereact-joi-validation\u003c/h2\u003e\n\u003c/p\u003e\n\n[![npm](https://img.shields.io/npm/dm/react-joi-validation.svg)]()\n[![Build Status](https://travis-ci.org/greena13/react-joi-validation.svg)](https://travis-ci.org/greena13/react-joi-validation)\n[![GitHub license](https://img.shields.io/github/license/greena13/react-joi-validation.svg)](https://github.com/greena13/react-joi-validation/blob/master/LICENSE)\n\n## Features\n\n* Extremely flexible and easy to integrate with your data persistence and UI layers\n* Validate all or some of a component's values\n* Can be used for form validation or with any other component you like\n* Use the powerful declarative [Joi API](https://github.com/hapijs/joi/blob/master/API.md) or write your own validator functions - or both!\n* Does not include Joi as a dependency to remain light weight, allow gradual integration into your projects and to remain environment agnostic - just point `react-joi-validation` at the version of Joi that is right for your project's environment and it will use it.\n* Transparently handles client and server data validations\n\n\n## Usage\n\n```javascript\nimport validate from 'react-joi-validation';\n\nvar schema = Joi.object().keys({\n  username: Joi.string().required(),\n  password: Joi.string().min(8).required()\n});\n\nclass MyComponent extends Component {\n  render() {\n    const {\n      user: { username, password },\n      errors, changeHandler, validateHandler\n    } = this.props;\n\n    return(\n      \u003cdiv \u003e\n        \u003cinput type=\"text\"\n          value={username}\n          onChange={ changeHandler('username') }\n          onBlur={ validateHandler('username') }\n        /\u003e\n\n        \u003cspan className={style.error}\u003e { errors.username } \u003c/span\u003e\n\n        \u003cinput type=\"password\"\n          value={password}\n          onChange={ changeHandler('password') }\n          onBlur={ validateHandler('password') }\n        /\u003e\n\n        \u003cspan className={style.error}\u003e { errors.password } \u003c/span\u003e\n\n        \u003cinput type=\"Submit\" value=\"Sign In\" /\u003e\n      \u003c/div\u003e\n    );\n  }\n}\n\nMyComponent.defaultProps = {\n  username: '',\n  password: ''\n};\n\nvar validationOptions = {\n  joiSchema: schema,\n  only: 'user'\n};\n\nvalidate(MyComponent, validationOptions)\n```\n## Installation\n\n```bash\nnpm install react-joi-validation --save\n```\n\nIf you are planning on using `react-joi-validations` with Joi, you also need to follow the installation instructions for the version and type of Joi you wish to use. [joi-browser](https://github.com/jeffbski/joi-browser) is recommended for web applications.\n\nOnce you have a version of Joi installed, just let `react-joi-validations` know about it somewhere near the entry point of your code (before any other calls to `react-joi-validations`):\n\n```javascript\nimport ReactJoiValidations from 'react-joi-validation'\nimport Joi from 'joi-browser' // or whatever Joi library you are using\n\nReactJoiValidations.setJoi(Joi);\n```\n\n\n## What version of Joi should I use?\n\nJoi is not listed as a peer dependency for `react-joi-validation` as there are many flavours and forks of Joi out there that provide similar behaviour and APIs in different environments and `react-joi-validation` should work with any of them. In fact, you do not need to use Joi at all if you do not want to.\n\n`react-joi-validation` was developed and tested using [joi-browser](https://github.com/jeffbski/joi-browser) in a client-side environment.\n\n## How it works\n\n`react-joi-validation` works by providing a higher order function that wraps any component you wish to validate. It maintains values in its own state and passes them down to your component as props, along with a number of functions you can use to update and validate those values as the user interacts with your component.\n\n The validator component merges the values you define in your component's `defaultProps`, the values you pass the validator component's `props` and the values you set using change handlers when the user interacts with your UI.\n\n It then runs these merged values through a Joi schema that you provide and/or one or more validator functions you define. The resultant error object is merged with errors passed to the validator components `props` (allowing you to validate with your server or some other external party) and passed down to your component.\n\n### Guiding concepts\n\n * **Succinct and expressive syntax** - `react-joi-validation` removes the need in most cases for defining handlers for user events. You can do them inline for your UI at render time, or add a line to your existing event handler methods if you need custom logic or easy integration with your existing code.\n * **Complete UI independence** - `react-joi-validation` wraps your component and provides change handlers and an error object. What you do with those errors and how you display them is entirely up to you.\n * **Separation of change and validation events** - the validation of values is done separately to maintaining the changes to those values. Often you want to validate a user's input only after they have completed entering it. Because of this decoupling, you can even validate fields other than those that were just changed. This allows validating groups of values when the user has completed setting the final value.\n * **Selective, explicit validation** - `react-joi-validation` makes validating each value explicit, so you can validate a user's input as they do it, rather than validating all fields before the user has even got to them.\n * **Full validation flexibility** - you can chose to use Joi or your own validator functions or trigger events that pass errors in as `props`, making it easy to integrate with any existing project.\n * **Easy integration with external validation** - in addition to the validation `react-joi-validation` performs, it also allows passing in errors from external sources such as errors from your server. It transparently merges them with the `react-joi-validation` errors.\n * **Flexible default values** - it's possible to set defaults for values using either the component's `defaultProps` or the `props` to the validator component (or both). This makes it possible to set default values dynamically at runtime.\n\n\n## Higher Order Function API\n\n### Using Joi\n\n#### Passing a validation schema\n\nJoi has a very powerful, declarative [API](https://github.com/hapijs/joi/blob/master/API.md). You can use any object that `Joi.validate` would normally accept as a schema, this includes:\n\n\u003e a joi type object or a plain object where every key is assigned a joi type object\n\nYou pass it using the `joiSchema` option:\n\n```javascript\nvar schema = {\n  a: Joi.string()\n};\n\nvalidate(MyComponent, { joiSchema: schema })\n```\n\n#### Configuring Validation\n\nYou can configure Joi's validation by passing an object to `joiOptions` that contains any of `Joi.validate`'s [supported options](https://github.com/hapijs/joi/blob/master/API.md#validatevalue-schema-options-callback).\n\n ```javascript\n validate(MyComponent, { joiSchema: schema, joiOptions: { allowUnknown: true }})\n```\n\nBy default, each validation is performed with `abortEarly` option set to false, so all errors are shown - not just the first encountered. This can be overridden, however:\n\n```javascript\n validate(MyComponent, { joiSchema: schema, joiOptions: { abortEarly: true }})\n```\n\n### Scoping validation\n\n#### Validating all of a component's props\n\nBy default, `react-joi-validation` will validate all props passed to your component, so you do not need to do anything additional.\n\n#### Validating a single prop\n\nIf you only want to validate a single prop and ignore all others, you can use the `only` option\n\n```javascript\nvalidate(MyComponent, { only: 'user', joiSchema: schema })\n```\n\nThis applies the validation `schema` to the `user` prop only, (so you do not need to nest your validation under `user`):\n\n```javascript\n// This would work as intended\nvar schema = Joi.object().keys({\n  username: Joi.string().required(),\n  password: Joi.string().min(8).required()\n});\n\n// This would also work\nvar schema = {\n  username: Joi.string().required(),\n  password: Joi.string().min(8).required()\n};\n\n// This would NOT work\nvar schema = {\n  user: Joi.object().keys({\n    username: Joi.string().required(),\n    password: Joi.string().min(8).required()\n  })\n};\n```\n\n#### Validating multiple props\n\nWhen the `only` option is passed an array, it applies `schema` to an object with only those values and excludes all others.\n\n```javascript\nvar schema = {\n  user: Joi.object().keys({\n    username: Joi.string().required(),\n    password: Joi.string().min(8).required()\n  }),\n\n  order: Joi.object().keys({\n    number: Joi.number().required()\n  })\n};\n\nvalidate(MyComponent, { only: ['user', 'order'], joiSchema: schema })\n\n//...\n\n\u003cMyComponent user={user} order={order} message={message}/\u003e\n```\nAn point of note is that `only: [user]` is **not** the same as `only: 'user'`. The former applies `schema` to `{ user: \u003cuser\u003e }` while the latter applies it to `\u003cuser\u003e`.\n\n### Using a validator function\n\nIn addition to, or instead of, a Joi schema, you can pass a custom validator function using the `validator` option:\n\n```javascript\nvalidate(MyComponent, { validator: myValidatorFunction })\n```\n\nThis is useful for performing validation not possible with the Joi syntax. Please refer to the [validator function interface](#validator-function-interface) section for more information.\n\n#### Chaining validators\n\nYou can also use more than one validator at a time by providing an array to `validators`. The validators are executed in the order that they appear in the array and the `values` and `errors` passed to the callback by each validator are given to the next one in the chain. The `values` and `errors` outpu by the final validator are saved in the validator component.\n\n```javascript\nvalidate(MyComponent, { validator: [ validator1, validator2 ] })\n```\n\n### Pseudovalues\n\nSometimes it is convenient to have your validator place error messages on attributes of `errors` that do not correspond with any of the actual values being passed down. One example of this is a user must select at least one option from either of two lists and an error message doesn't really fit on either of the individual lists.\n\nYou can achieve this using pseudovalues, which are like extra hooks to hang your error messages on. They do not have values or get passed down to the wrapped component, but they can place errors into the `errors` prop. They can also be the target of a validation action.\n\n`pseudoValues` accepts either a string or an array of strings, indicating the names of the pseudovalues you would like to use.\n\n```javascript\n\nfunction validateAtLeastOneProductOrService({ valuesWithDefaults, values, validateAllValues, validatedValues, errors }, callback){\n  const { products, services } = valuesWithDefaults;\n\n  if (validateAllValues || validatedValues.includes('billableItems')) {\n    if (products.length === 0 \u0026\u0026 services.length === 0) {\n      errors.billableItems = 'Must select at least one product or service';\n    }\n  }\n\n  callback({ values, errors });\n}\n\nvalidate(MyComponent, { validator: validateAtLeastOneProductOrService, pseudoValues: ['billableItems'] })\n\n// MyComponent.js\n\n// ...\n\n\u003cFormError\u003e\n  { errors.billableItems }\n\u003c/FormError\u003e\n\n// ...\n\n\u003cproduct onClick={ changeHandler('product', { value: id, validate: 'billableItems' }) }\u003e\n  Product {id}\n\u003c/product\u003e\n\n```\n\n### Setting errors, externally\n\nBy default, `react-joi-validation` will merge any errors passed on the props `errors` with those resultant from validating the user input. This is useful for displaying validation errors from your server, or outside of your component. When the value is changed, it is marked as \"touched\" and any corresponding external errors are no longer present on the `errors` prop passed down to your component.\n\nThis means you can validate data externally and display the error until the user first changes its value (and the external error becomes stale). It then falls to local validation again before you to pass it back up to you server or external validation module for re-evaluating.\n\nThe prop used for external errors can be set using the `externalErrorsPath` option. This does **not** change the prop passed down to your component. That is always `this.props.errors`.\n\n\n```javascript\n const MyValidatedComponent = validate(MyComponent, { joiSchema: schema, externalErrorsPath: 'response.errors'})\n\n \u003cMyValidatedComponent response={ { errors } } /\u003e\n\n```\n\n## Wrapped Component API\n\nWhen working with your component that is wrapped by `react-joi-validations`, two types of functions are provided to you:\n\n* Functions that return handlers for dealing with various events that give you a convenient for scoping simple event handling\n* The event handlers themselves for when you need to wrap your event handling in some custom logic\n\n### Updating values\n\nThese helpers are for when you want to update the state of the validation component so it has the correct values to perform validation against. They do not actually trigger validation, unless otherwise specified.\n\n#### changeHandler\n\n`changeHandler` is for when you simply want to keep a value in sync with what appears on the UI. It accepts the name of the value to update and an optional set of configuration object. It returns a function that will accept an event object as the first argument and the new value as the second.\n\n```javascript\nconst { user: { username }, changeHandler } = this.props;\n\nreturn(\n  \u003cdiv\u003e\n    \u003cinput value={username} onChange={changeHandler('username')} /\u003e\n  \u003c/div\u003e\n)\n```\n\nBy default `react-joi-validation`'s `changeHandler` function will return a handler that will try and guess which argument it should use as the value for validation when it is called. This should cover 90% of use cases, as it handles the event handler signature used by the standard `\u003cinput /\u003e` tag.\n\nThere are 3 places you can specify an alternative strategy to use:\n\n* The `setChangeHandlerStrategy()` function sets the default handler strategy that should be used globally - it only needs to be called once at the entry point of your application.\n\n```\nimport ReactJoiValidations, { guessCorrectValue } from 'react-joi-validation'\n\nReactJoiValidations.setChangeHandlerStrategy(guessCorrectValue);\n```\n\n* The `changeHandlerStrategy` option can be passed to `validate` and sets the default handler strategy for a single component and takes precedence over any default specified using `setChangeHandlerStrategy()`:\n\n```\nimport validate, { guessCorrectValue } from 'react-joi-validation'\n\nvar validationOptions = {\n  joiSchema: schema,\n  only: 'user',\n  changeHandlerStrategy: guessCorrectValue,\n};\n\nvalidate(MyComponent, validationOptions)\n```\n\n* The `strategy` option can be passed to `changeHandler` and sets the handler strategy for a single change handler and takes precedence over any default specified using `setChangeHandlerStrategy()` or `changeHandlerStrategy`:\n\n```\nimport validate, { guessCorrectValue } from 'react-joi-validation'\n\n\u003cproduct onClick={ changeHandler('product', { startegy: guessCorrectValue }) }\u003e\n  Product {id}\n\u003c/product\u003e\n```\n\n`react-joi-validation` exports several pre-defined strategies you can import directly into your project:\n\n* `guessCorrectValue` - (Default) Uses `firstArg.event.target` if it's present, otherwise uses `secondArg`.\n* `useFirstArgument` - Uses the (entire) first argument and ignores all others\n* `useSecondArgument` - Uses the second argument and ignores all others\n* `useThirdArgument` - Uses the third argument and ignores all others\n* `useEventTargetValue` - Uses `firstArg.event.target` (and returns `undefined` when it is not present)\n\nIf these do not cover what you need, you can pass a custom function that returns the value that should be used for validation every time the change handler is called:\n\n```\nimport validate, { guessCorrectValue } from 'react-joi-validation'\n\nvar validationOptions = {\n  joiSchema: schema,\n  only: 'user',\n  changeHandlerStrategy: (arg1, arg2) =\u003e {\n    return arg2.really.strange.format[0].value;\n  },\n};\n\nvalidate(MyComponent, validationOptions)\n```\n\n\u003e Change handler strategies are ignored when the `changeHandler`'s `value` option is also used\n\n##### Validating on every change\n\nIf you want to validate on every change, you can do so using the options argument:\n\n```javascript\nreturn(\n  \u003cinput value={username} onChange={changeHandler('username', { validate: true })} /\u003e\n)\n```\n\nYou can also validate a field other than the one you are modifying by providing it as a string instead of `true` to the `validate` option.\n\n##### Setting value on render\n\nYou can set the value a user interaction will have at render time using the `options.value` argument:\n\n```javascript\nreturn(\n  \u003cinput type='button' value={termsAndConditions} onChange={changeHandler('username', { value: true })} /\u003e\n)\n```\n\n#### changeValue\n\n`changeValue` is for whenever `changeHandler` is not flexible enough. It accepts the name of the value to change and the new value.\n\n```javascript\nrender() {\n  const { user: { username } } = this.props;\n\n  return(\n    \u003cdiv\u003e\n      \u003cinput value={username} onChange={this.handleUsernameChange} /\u003e\n    \u003c/div\u003e\n  )\n}\n\nhandleUsernameChange(event, newUsername){\n  const { changeValue } = this.props;\n\n  // custom code here\n  changeValue('username', newUsername)\n}\n```\n\n### Changing multiple values at once\n\n#### changesHandler\n\nSimilar to `changeHandler`, but accepts an array of path-value tuples that list the changes to be made.\n\n```javascript\nreturn(\n  \u003cbutton onChange={changesHandler([['username', ''], ['password', '']])}   \u003e\n    Clear\n  \u003c/button\u003e\n)\n```\n\n`changesHandler` accepts the same options as `changeHandler`. If `validate: true` is used, all values listed in the array are validated.\n\n#### changeValues\n\nSimilar to `changeValue`, but accepts an array of path-value tuples that list the changes to be made.\n\n```javascript\nrender() {\n  return(\n    \u003cdiv\u003e\n      \u003cbutton onChange={this.handleClearValues} \u003e\n        Clear\n      \u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n\nhandleClearValues(event){\n  const { changeValues } = this.props;\n\n  // custom code here\n  changeValues([ ['username', ''], ['password', ''] ])\n}\n```\n\n`changeValues` accepts the same options as `changeValue`. If `validate: true` is used, all values listed in the array are validated.\n\n### Working with arrays\n\nAlthough you can work with the functions above to maintain array values, additional syntactic sugar has been provided:\n\n#### pushHandler\n\nSimilar to `changeHandler`, but rather than replace the value at the provided `path` with a new one, it will push the new value onto the end of the array stored at `path`. This is useful for when checkboxes are ticked or similar situations where new values need to be added to a list.\n\n`pushHandler` accepts all of the options that `changeHandler` does, and one extra:\n\n- `allowDuplicates` - (Default: `true`) Whether to push a value onto the array if that value is already in the list.\n\n```javascript\nrender() {\n  const { pushHandler, cities } = this.props;\n\n  return(\n    [\"Paris\", \"New York City\", \"London\"].map((city) =\u003e {\n      return(\n        \u003cinput type='button' label={ \"Add \" + city } onClick={ pushHandler('cities') } /\u003e\n      );\n    }\n  );\n}\n```\n\n#### pushValue\n\n`pushValue` is for whenever `pushHandler` is not flexible enough. It accepts a `path` to an array to push a `value` to.\n\n`pushValue` accepts all of the options that `changeValue` does, and one extra:\n\n- `allowDuplicates` - (Default: `true`) Whether to push a value onto the array if that value is already in the list.\n\n```javascript\nrender() {\n  return(\n    [\"Paris\", \"New York City\", \"London\"].map((city) =\u003e {\n      return(\n        \u003cinput type='button' label={ \"Add \" + city } onClick={ this.handleAddCity(city) } /\u003e\n      );\n    }\n  );\n}\n\nhandleAddCity(city) {\n   const { pushValue, cities } = this.props;\n\n   if (cities.indexOf(city) === -1 ) {\n      pushValue('cities', city);\n   }\n}\n```\n\n#### togglePushHandler\n\nReturns a function that, when called, pushes a value onto the end of an array if that value is not already in the array, otherwise it removes it. i.e. it toggles that value's inclusion in the array.\n\n`togglePushHandler` accepts all of the options that `changeHandler` does.\n\n```javascript\nrender() {\n  const { togglePushHandler, cities } = this.props;\n\n  return(\n    [\"Paris\", \"New York City\", \"London\"].map((city) =\u003e {\n      return(\n        \u003clabel\u003e\n            \u003cinput type='checkbox' onClick={ togglePushHandler('cities') } /\u003e\n            { city }\n        \u003c/label\u003e\n      );\n    }\n  );\n}\n```\n\n#### togglePushValue\n\nPushes a value onto the end of an array if that value is not already in the array, otherwise it removes it. i.e. it toggles that value's inclusion in the array.\n\n`togglePushValue` accepts all of the options that `changeValue` does.\n\n```javascript\nrender() {\n  return(\n    [\"Paris\", \"New York City\", \"London\"].map((city) =\u003e {\n      return(\n        \u003clabel\u003e\n            \u003cinput type='checkbox' onClick={ this.handleToggleCity('cities') } /\u003e\n            { city }\n        \u003c/label\u003e\n      );\n    }\n  );\n}\n\nhandleToggleCity(city) {\n   const { togglePushHandler, cities } = this.props;\n\n  togglePushHandler('cities', city);\n}\n```\n\n#### unshiftHandler\n\nSimilar to `pushHandler`, but will add the new value to the *beginning* of an array, rather than at the end.\n\n`unshiftHandler` accepts all of the options that `pushHandler` does, and one extra:\n\n- `allowDuplicates` - (Default: `true`) Whether to unshift a value onto the array if that value is already in the list.\n\n#### unshiftValue\n\nSimilar to `pushValue`, but will add the new value to the *beginning* of an array, rather than at the end.\n\n`unshiftValue` accepts all of the options that `changeValue` does, and one extra:\n\n- `allowDuplicates` - (Default: `true`) Whether to push a value onto the array if that value is already in the list.\n\n#### toggleUnshiftHandler\n\nSimilar to togglePushHandler, but instead the returned function, when called, adds a value to the start of an array if that value is not already in the array, otherwise it removes it. i.e. it toggles that value's inclusion in the array.\n\n`toggleUnshiftHandler` accepts all of the options that `changeHandler` does.\n\n#### toggleUnshiftValue\n\nSimilar to togglePushValue, but instead it adds a value to the start of an array if that value is not already in the array, otherwise it removes it. i.e. it toggles that value's inclusion in the array.\n\n`toggleUnshiftValue` accepts all of the options that `changeValue` does.\n\n\n#### pullHandler\n\nThe opposite of `pushHandler` and `unshiftHandler`, `pullHandler` will remove one or more elements from an array stored at `path`.\n\n`pullHandler` accepts a `path` to the array to remove an element from, and an `options` hash. It returns a handler function, that when called, will remove the value passed to it from the array.\n\nExactly how this is done depends on what options are provided:\n\n* `\u003cno options\u003e` - (Default) Only the *first* instance of the value passed to the handler will be removed from the array at `path`.\n* `index=\u003cint\u003e` - The element at the specified index will be removed from the array at `path`\n* `removeAllInstances` - When set to `true`, (default is `false`), *all* instances of the value passed to the handler will be removed from the array at `path`.\n\nDefault behaviour:\n\n```javascript\nrender() {\n  const { pullHandler, pullHandler, cities } = this.props;\n\n  return(\n    cities.map((city) =\u003e {\n      return(\n        \u003cinput type='button' label={ \"Remove \" + city } onClick={ pullHandler('cities') } /\u003e\n      );\n    }\n  );\n}\n```\n\nUsing the `index` option:\n\n```javascript\nrender() {\n  const { pullHandler, pullHandler, cities } = this.props;\n\n  return(\n    cities.map((city, index) =\u003e {\n      return(\n        \u003cinput type='button' label={ \"Remove \" + city } onClick={ pullHandler('cities', { index: index }) } /\u003e\n      );\n    }\n  );\n}\n```\n\nUsing the `removeAllInstances` option:\n\n```javascript\nrender() {\n  const { pullHandler, cities } = this.props;\n\n  return(\n    cities.map((city, index) =\u003e {\n      return(\n        \u003cinput type='button' label={ \"Remove \" + city } onClick={ pullHandler('cities', { removeAllInstances: true }) } /\u003e\n      );\n    }\n  );\n}\n```\n\n#### pullValue\n\n`pullValue` is for whenever `pullHandler` is not flexible enough. It accepts a `path` to an array to remove a `value` from.\n\n`pullValue` accepts all of the options that `pullHandler` does.\n\n```javascript\nrender() {\n  const { cities } = this.props;\n\n  return(\n    cities.map((city, index) =\u003e {\n      return(\n        \u003cinput type='button' label={ \"Remove \" + city } onClick={ this.handleRemoveCity } /\u003e\n      );\n    }\n  );\n}\n\nhandleRemoveCity(city) {\n   const { pullValue, cities, user } = this.props;\n\n   if (user.isAdmin) {\n      pullValue('cities', city);\n   }\n}\n```\n\n### Accessing Errors\n\nA component's errors are accessible via the `errors` prop, which is an object keyed by value names. If the object is empty, then there are no errors.\n\n### Triggering validation\n\n`react-joi-validation` was designed with form validation in mind. As such, it only validates values the values that it is told to, when it is told to. This makes it trivial to validate each field after the user has interacted with it, leaving the rest of the form error free.\n\n\n```javascript\n\nrender() {\n  const { user: { username }, errors } = this.props;\n\n  return(\n    \u003cdiv\u003e\n      \u003cinput value={username} /\u003e\n\n      \u003cspan style={styles.error}\u003e\n        { errors.username }\n      \u003c/span\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\nDepending on the options you pass to `only`, the errors may be nested more deeply: e.g. `errors.user.username`.\n\n#### validateHandler\n\n`validateHandler` is for simple cases where you just want validate a single value after a particular event (such as when a field loses focus). It accepts either the name of the value it should validate, or an array of values it should validate as the first argument and an optional callback for once the validation has been complete as the second argument.\n\n##### Validating a single value\n\n```javascript\nconst { user: { username }, changeHandler, validateHandler } = this.props;\n\nreturn(\n  \u003cdiv\u003e\n    \u003cinput value={username}\n      onChange={changeHandler('username')}\n      onBlur={validateHandler('username')}\n    /\u003e\n  \u003c/div\u003e\n)\n```\n\n##### Validating multiple values at once\n\n```javascript\nconst { address: { country, postcode }, changeHandler, validateHandler } = this.props;\n\nreturn(\n  \u003cdiv\u003e\n    \u003cinput value={postcode}\n      onChange={changeHandler('postcode')}\n    /\u003e\n\n    \u003cinput value={country}\n      onChange={changeHandler('country')}\n      onBlur={validateHandler(['postcode','country'])}\n    /\u003e\n  \u003c/div\u003e\n)\n```\n\n#### validate\n\n`validate` is for whenever `validateHandler` is not flexible enough. It accepts the name of the value to validate.\n\n```javascript\nrender() {\n  const { user: { username }, changeHandler } = this.props;\n\n  return(\n    \u003cdiv\u003e\n      \u003cinput value={username}\n        onChange={changeHandler('username')}\n        onBlur={this.handleUsernameValidation}\n      /\u003e\n    \u003c/div\u003e\n  )\n}\n\nhandleUsernameValidation(event){\n  const { validate } = this.props;\n\n  // custom code here\n\n  validate('username')\n}\n```\n\n#### validateAllHandler\n\n`validateAllHandler` is for simple cases where you want to validate all values currently in the validation component's state (including values set by `defaultProps` and passed in as props). It accepts a callback to be executed when the validation is complete (and the current `errors` object is available in props).\n\n```javascript\nrender() {\n  const { user: { username }, changeHandler, validateAllHandler } = this.props;\n\n  return(\n    \u003cdiv\u003e\n      \u003cinput value={username}\n        onChange={changeHandler('username')}\n      /\u003e\n\n      \u003cinput type=\"submit\" onClick={validateAllHandler(this.handleValidation)} /\u003e\n    \u003c/div\u003e\n  )\n}\n\nhandleValidation(){\n  const { errors } = this.props;\n\n  if (!any(errors)) {\n    // navigate away\n  }\n}\n```\n\n#### validateAll\n\n`validateAll` is for when `validateAllHandler` is not flexible enough. It accepts a callback as it's only argument, which is invoked when the validation has been completed.\n\n```javascript\nrender() {\n  const { user: { username }, changeHandler } = this.props;\n\n  return(\n    \u003cdiv\u003e\n      \u003cinput value={username}\n        onChange={changeHandler('username')}\n      /\u003e\n\n      \u003cinput type=\"submit\" onClick={this.handleValidation} /\u003e\n    \u003c/div\u003e\n  )\n}\n\nhandleValidation(){\n  const { validateAll } = this.props;\n\n  // custom code here\n\n  validateAll(() =\u003e {\n    const { errors } = this.props;\n\n    if (!any(errors)) {\n      // navigate away\n    }\n  });\n}\n```\n\n### Clearing the validation state\n\n#### Clearing validation errors\n\nIt's possible to clear the validation errors for some or all of the data your component is managing. Calling `clearValidation` with no arguments will clear all errors. You can selectively clear validation errors for individual attributes by passing a path as a string or array of path strings.\n\n```javascript\nhandleValidation() {\n  const { clearValidation, overrideValidation } = this.props;\n\n  if (overrideValidation) {\n    clearValidation(); // or clearValidation('user.username')\n  }\n}\n```\n\n#### Clearing validation errors and resetting values\n\nIf you want to reset some or all attributes back to their default values (or the values  passed in as props) and clear the corresponding validation errors, it can be done using the `clearValidationAndResetValues`. Similar to `clearValidation`, it can be called with no arguments to clear all errors and values or with paths to selectively clear attributes and any corresponding validation errors.\n\nThis is useful when you want to pass responsibility for the data out of the component (say, to place it in your store, or to send to your server for validation). You  need to clear the validation component's state so when the data is passed back in via `props` to the component after having come back from your server or been persisted to your store, the validation component's state values don't take precedence.\n\n```javascript\nhandleValidation(){\n  const { validateAll } = this.props;\n\n  // custom code here\n\n  validateAll(() =\u003e {\n    const { errors, clearValidationAndResetValues } = this.props;\n\n    if (!any(errors)) {\n      // send to your store or server\n\n      this.clearValidationAndResetValues()\n    }\n  });\n}\n```\n\n## Validator function interface\n\nA custom validator function can be used with or instead of a Joi validation schema. It is passed using the `validator` option to the higher order component API (see [Using a validator function](#using-a-validator-function) for details).\n\nThe function must accept two arguments: an object of options and a callback. The options object contains the following values:\n\n**OK to modify or replace:**\n* `values` - an object of values that will replace the current state when the validation is complete. This is used both for inspecting the current values and can be mutated to replace them. It represents only those values set using one of the `changeXXX` methods. It does not include default values set using the validator component's props or the wrapped component's `defaultProps`.\n* `errors` - an object of the errors output by the Joi validation, if a `joiSchema` was provided to `react-joi-validation` (otherwise an empty object). This give the function the opportunity to see if Joi detected any invalid attributes and to override them by mutating the object.\n\n**Do not modify or replace:**\n\n* `valuesWithDefaults` - an object containing the deeply merged values stored in state with the default values set using props and the wrapped component's `defaultProps`. This is the actual object used internally for validating with the Joi schema, and passed down as props to the wrapped component.\n* `validateAllValues` - a boolean indicating whether all values should be validated (including those not listed in `validatedValues`). Useful for only running the custom validations when all values should be present.\n* `validatedValues` - an array of value paths (strings) that record which values should be validated. Should be used in conjunction with `validateAllValues` to decide if you should validate particular fields even when they are not listed in `validatedValues`.\n* `changingValues` - an array of value paths that indicate which values have changed since the last time the validator was called. This is useful for only modifying `values` when certain fields are modified.\n* `props` - the props passed to the validator component. This is useful when the `only` option is in effect, for using prop values outside the validation schema to validate values in it.\n\n\nThe function **must** call the callback with an object containing two attributes:\n* `values`: the object of values, which may be unchanged or mutated by the validator function\n* `errors`: the object of errors, which may be unchanged or mutated by the validator function\n\n```javascript\nfunction validateSquareNumberOfImages({ values, validateAllValues, validatedValues, errors }, callback){\n  const { images } = values;\n\n  if (validateAllValues || includes(validatedValues, 'images')) {\n    if (isSquareNumber(images.length) ) {\n      errors['images'] = 'Must select a square number of images';\n    }\n  }\n\n  callback({ values, errors });\n}\n```\n\n## Running the test suite\n\nYou can run the complete test suite using the following command:\n\n```bash\nnpm run tests\n```\n\nIf you are creating a contribution and would like to run the tests whenever you save a file:\n\n```bash\nnpm run watch-tests\n```\n\n## Contributions\n\nAll contributions are welcome and encouraged.\n\n## Similar libraries\n\nIf `react-joi-validation` does not meet your needs for whatever reason, you may want to check out [react-validation-mixin](https://github.com/jurassix/react-validation-mixin).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreena13%2Freact-joi-validation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgreena13%2Freact-joi-validation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgreena13%2Freact-joi-validation/lists"}