UNPKG

react-jsonschema-form-validation

Version:
281 lines (236 loc) 8.97 kB
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties"; import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray"; import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2"; import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck"; import _createClass from "@babel/runtime/helpers/esm/createClass"; import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn"; import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf"; import _inherits from "@babel/runtime/helpers/esm/inherits"; import Ajv from 'ajv'; import classnames from 'classnames'; import throttle from 'lodash.throttle'; import memoize from 'memoize-one'; import React, { PureComponent } from 'react'; import scrollToElement from 'scroll-to-element'; import FormContext from './Context'; import { createAjv, filterByFieldNameWithWildcard, formatData, formatErrors, updateDataFromEvents } from './helpers'; // eslint-disable-next-line react/jsx-props-no-spreading var DefaultFormComponent = function DefaultFormComponent(props) { return React.createElement("form", Object.assign({ noValidate: true }, props)); }; var initialState = { errors: [], isSubmitted: false, touchedFields: [], valid: true }; var Form = /*#__PURE__*/ function (_PureComponent) { _inherits(Form, _PureComponent); function Form() { var _getPrototypeOf2; var _this; _classCallCheck(this, Form); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Form)).call.apply(_getPrototypeOf2, [this].concat(args))); _this.state = _objectSpread({}, initialState); _this.memoGetClassnames = memoize(function (className, isSubmitted) { return classnames('Jfv_Form', className, { isSubmitted: isSubmitted }); }); _this.memoGetContext = memoize(function (state, errorMessages) { return _objectSpread({}, state, { errorMessages: errorMessages, getFieldErrors: _this.getFieldErrors, handleFieldChange: _this.handleFieldChange, isFieldTouched: _this.isFieldTouched, isFieldInvalid: _this.isFieldInvalid, isTouched: _this.isTouched, touch: _this.touch }); }); _this.memoGetValidator = memoize(function (ajv, schema, throttleDuration) { var validate = ajv.compile(schema); var validator = function validator(data) { var formattedData = formatData(data); var valid = validate(formattedData); var errors = formatErrors(validate.errors); _this.setState({ valid: valid, errors: errors }); }; if (_this.throttledValidator) _this.throttledValidator.cancel(); _this.throttledValidator = throttle(validator, throttleDuration); return memoize(_this.throttledValidator); }); _this.getClassnames = function () { var className = _this.props.className; var isSubmitted = _this.state.isSubmitted; return _this.memoGetClassnames(className, isSubmitted); }; _this.getContext = function () { var errorMessages = _this.props.errorMessages; return _this.memoGetContext(_this.state, errorMessages); }; _this.getFieldErrors = function (fieldNames) { fieldNames = Array.isArray(fieldNames) ? fieldNames : [fieldNames]; var errors = _this.state.errors; return fieldNames.reduce(function (fieldsErrors, fieldName) { return [].concat(_toConsumableArray(fieldsErrors), _toConsumableArray(filterByFieldNameWithWildcard(errors, fieldName))); }, []); }; _this.getValidator = function () { var _this$props = _this.props, ajv = _this$props.ajv, schema = _this$props.schema, throttleDuration = _this$props.throttleDuration; return _this.memoGetValidator(ajv, schema, throttleDuration); }; _this.handleFieldChange = function (event, value) { var _this$props2 = _this.props, data = _this$props2.data, onChange = _this$props2.onChange; if (onChange) { if (typeof event === 'string') { event = { target: { name: event, value: value } }; } var newData = updateDataFromEvents(data, event); onChange(newData, event); } }; _this.handleSubmit = function (event) { event.preventDefault(); _this.submit(event); }; _this.handleSubmitError = function () { var scrollToError = _this.props.scrollToError; var errors = _this.state.errors; if (process.env.REACT_APP_JFV_DEBUG === 'true') console.log(errors); // eslint-disable-line no-console if (scrollToError) _this.scrollToFirstError(); }; _this.handleSubmitSuccess = function (event) { var onSubmit = _this.props.onSubmit; _this.reset(); onSubmit(event); }; _this.isFieldInvalid = function (fieldNames) { var _this2; fieldNames = Array.isArray(fieldNames) ? fieldNames : [fieldNames]; return (_this2 = _this).getFieldErrors.apply(_this2, _toConsumableArray(fieldNames)).length > 0; }; _this.isFieldTouched = function (fieldNames) { fieldNames = Array.isArray(fieldNames) ? fieldNames : [fieldNames]; var touchedFields = _this.state.touchedFields; return !!fieldNames.find(function (fieldName) { return filterByFieldNameWithWildcard(touchedFields.map(function (field) { return { field: field }; }), fieldName).length > 0; }); }; _this.isTouched = function () { var touchedFields = _this.state.touchedFields; return !!touchedFields.length; }; _this.reset = function () { return _this.setState(initialState); }; _this.scrollToFirstError = function () { var scrollOptions = _this.props.scrollOptions; var errors = _this.state.errors; var firstError = errors[0]; var element = document.getElementsByName(firstError.field)[0]; scrollToElement(element, scrollOptions); }; _this.submit = function (event) { var valid = _this.state.valid; _this.setState({ isSubmitted: true }); if (valid) _this.handleSubmitSuccess(event);else _this.handleSubmitError(); }; _this.touch = function (fieldNames) { fieldNames = Array.isArray(fieldNames) ? fieldNames : [fieldNames]; var touchedFields = _this.state.touchedFields; _this.setState({ touchedFields: _toConsumableArray(new Set([].concat(_toConsumableArray(touchedFields), _toConsumableArray(fieldNames)))) }); }; _this.validate = function () { var data = _this.props.data; var validate = _this.getValidator(); validate(data); }; return _this; } _createClass(Form, [{ key: "componentDidMount", value: function componentDidMount() { this.validate(); } }, { key: "componentDidUpdate", value: function componentDidUpdate() { this.validate(); } }, { key: "componentWillUnmount", value: function componentWillUnmount() { if (this.throttledValidator) this.throttledValidator.cancel(); } }, { key: "render", value: function render() { var _this$props3 = this.props, ajv = _this$props3.ajv, children = _this$props3.children, className = _this$props3.className, FormComponent = _this$props3.component, data = _this$props3.data, throttleDuration = _this$props3.throttleDuration, errorMessages = _this$props3.errorMessages, onChange = _this$props3.onChange, onSubmit = _this$props3.onSubmit, schema = _this$props3.schema, scrollOptions = _this$props3.scrollOptions, scrollToError = _this$props3.scrollToError, props = _objectWithoutProperties(_this$props3, ["ajv", "children", "className", "component", "data", "throttleDuration", "errorMessages", "onChange", "onSubmit", "schema", "scrollOptions", "scrollToError"]); return React.createElement(FormContext.Provider, { value: this.getContext() }, React.createElement(FormComponent, Object.assign({ className: this.getClassnames(), onSubmit: this.handleSubmit // eslint-disable-next-line react/jsx-props-no-spreading }, props), children)); } }]); return Form; }(PureComponent); Form.defaultProps = { ajv: createAjv(), children: null, className: '', component: DefaultFormComponent, data: {}, errorMessages: {}, onChange: null, scrollToError: true, scrollOptions: { offset: 0, align: 'middle', duration: 900 }, throttleDuration: 200 }; export default Form;