From 27d29d65805edd1987a01eea08a1692e83a1ba6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mariusz=20Przoda=C5=82a?= Date: Mon, 2 Dec 2019 19:16:20 +0100 Subject: [PATCH] fix issue #82 ListField error handling --- src/components/FieldConnect.jsx | 54 ++++++++++++++++++++++----------- src/components/Form.jsx | 15 +++++++-- tests/integration/Form.test.jsx | 19 ++++++++++++ 3 files changed, 68 insertions(+), 20 deletions(-) diff --git a/src/components/FieldConnect.jsx b/src/components/FieldConnect.jsx index f7df1d1..9a2b484 100644 --- a/src/components/FieldConnect.jsx +++ b/src/components/FieldConnect.jsx @@ -1,6 +1,7 @@ import React from 'react'; -import isEqual from 'lodash/isEqual'; import PropTypes from 'prop-types'; +import isEqual from 'lodash/isEqual'; +import isEmpty from 'lodash/isEmpty'; import cloneDeep from 'lodash/cloneDeep'; export const FieldConnect = (Component) => { @@ -12,6 +13,19 @@ export const FieldConnect = (Component) => { this.shouldShowValidationErrors = false; this.fieldValidationErrors = null; this.fieldValidators = []; + + this.setFieldValidator = this.setFieldValidator.bind(this); + this.removeFieldValidator = this.removeFieldValidator.bind(this); + this.registerFieldValidators = this.registerFieldValidators.bind(this); + this.unregisterFieldValidators = this.unregisterFieldValidators.bind(this); + this.onChangeData = this.onChangeData.bind(this); + this.getPath = this.getPath.bind(this); + this.getPropsFromSchema = this.getPropsFromSchema.bind(this); + this.getEventsEmitter = this.getEventsEmitter.bind(this); + this.getValidationErrors = this.getValidationErrors.bind(this); + this.getFieldAttributes = this.getFieldAttributes.bind(this); + this.hasValidationError = this.hasValidationError.bind(this); + this.submit = this.submit.bind(this); } getChildContext() { @@ -47,7 +61,7 @@ export const FieldConnect = (Component) => { this.unregisterFieldValidators(); } - onChangeData = (value) => { + onChangeData(value) { const { name, callbacks: { onChange } } = this.props; const { setModel, @@ -84,11 +98,11 @@ export const FieldConnect = (Component) => { .join('.'); } - setFieldValidator = (validator) => { + setFieldValidator(validator) { const modelPath = this.getModelPath(); this.context.setValidator(modelPath, validator); this.fieldValidators.push(validator); - }; + } setCurrentFieldValue(value) { this.fieldValue = cloneDeep(value); @@ -108,16 +122,18 @@ export const FieldConnect = (Component) => { return fieldValue; } - getPropsFromSchema = () => { + getPropsFromSchema() { const { name } = this.props; const { getSchema } = this.context; if (typeof getSchema !== 'function') return undefined; return getSchema(name); } - getEventsEmitter = () => this.context.eventsEmitter; + getEventsEmitter() { + return this.context.eventsEmitter; + } - getValidationErrors = () => { + getValidationErrors() { const { name, callbacks: { onError } } = this.props; const { getValidationErrors } = this.context; this.shouldShowValidationErrors = this.shouldShowErrors(); @@ -129,14 +145,14 @@ export const FieldConnect = (Component) => { return results; } - getPath = () => { + getPath() { const { name } = this.props; const { getPath } = this.context; if (typeof getPath !== 'function') return name; return `${getPath()}.${name}`; - }; + } - getFieldAttributes = () => { + getFieldAttributes() { const { validateOnChange, isFormSubmitted } = this.context; const { fieldAttributes, callbacks: { onFocus, onBlur } } = this.props; return Object.assign( @@ -167,15 +183,15 @@ export const FieldConnect = (Component) => { } } - removeFieldValidator = (validator) => { + removeFieldValidator(validator) { const index = this.fieldValidators.indexOf(validator); if (index > -1) { this.context.removeValidator(validator); this.fieldValidators.splice(index, 1); } - }; + } - registerFieldValidators = () => { + registerFieldValidators() { if (this.props.validator) { const { getModel } = this.context; const fieldValidator = (...attr) => { @@ -184,13 +200,13 @@ export const FieldConnect = (Component) => { }; this.setFieldValidator(fieldValidator); } - }; + } - unregisterFieldValidators = () => { + unregisterFieldValidators() { this.fieldValidators.forEach((validator) => { this.context.removeValidator(validator); }); - }; + } shouldShowErrors() { const { hasBeenTouched, validateOnChange, isFormSubmitted } = this.context; @@ -202,7 +218,7 @@ export const FieldConnect = (Component) => { return hasBeenTouched(this.getPath()); } - submit = (event) => { + submit(event) { const { submitForm } = this.context; if (typeof submitForm !== 'function') return; submitForm(event); @@ -269,7 +285,9 @@ export const FieldConnect = (Component) => { } } - hasValidationError = () => this.getValidationErrors().length > 0; + hasValidationError() { + return !isEmpty(this.getValidationErrors()); + } render() { return ( { + if (isObject(error)) { + Object.keys(error).forEach((key) => { + schema.setModelError(`${path}.${key}`, error[key]); + }); + return; + } + schema.setModelError(path, error); +}; + class Form extends React.Component { constructor(props) { super(props); @@ -118,10 +129,10 @@ class Form extends React.Component { if (asyncValidationError && typeof asyncValidationError === 'boolean') { return asyncValidationError; } - return schema.setModelError(path, asyncValidationError); + return setErrorOnSchema(schema, path, asyncValidationError); }); } - return schema.setModelError(path, validationResults); + return setErrorOnSchema(schema, path, validationResults); }; this.fieldsValidators.push({ path, validator, schemaValidator }); if (typeof this.state.schema.validate === 'function') { diff --git a/tests/integration/Form.test.jsx b/tests/integration/Form.test.jsx index 520464e..f924866 100644 --- a/tests/integration/Form.test.jsx +++ b/tests/integration/Form.test.jsx @@ -11,6 +11,7 @@ import { FormEventsEmitter, ErrorField, } from '../../src/components'; +import { setErrorOnSchema } from '../../src/components/Form'; import FormController from '../../src/components/FormController'; import FieldConnect from '../../src/components/FieldConnect'; import { titleSchema, bookSchema, fooBarSchema } from '../data/schemas'; @@ -868,3 +869,21 @@ describe('Form', () => { }); }); }); + +describe('setErrorOnSchema', () => { + let schema; + beforeEach(() => { + schema = { + setModelError: jest.fn(), + }; + }); + + it('should set error on schema when error has object structure', () => { + setErrorOnSchema(schema, 'foo.0', { bar: 'barError' }); + expect(schema.setModelError).toHaveBeenCalledWith('foo.0.bar', 'barError'); + }); + it('should set error on schema when error is string', () => { + setErrorOnSchema(schema, 'foo.bar', 'barError'); + expect(schema.setModelError).toHaveBeenCalledWith('foo.bar', 'barError'); + }); +});