From 3300858983ba60575d5e939e839500addb8a9c8c Mon Sep 17 00:00:00 2001 From: Andrew Lessels Date: Mon, 17 Jul 2017 11:04:35 +1000 Subject: [PATCH] Fix touched behavior - Focus and blurring a field with validation rules without changing the value should not cause it to be 'touched' - Changing a field value back to it's initial value should restore the untouched state --- src/createBaseForm.js | 9 ++++- src/createFieldsStore.js | 6 ++++ src/createForm.js | 1 + tests/touched.spec.js | 76 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 tests/touched.spec.js diff --git a/src/createBaseForm.js b/src/createBaseForm.js index 4092d260..b0cb46cb 100644 --- a/src/createBaseForm.js +++ b/src/createBaseForm.js @@ -41,6 +41,7 @@ function createBaseForm(option = {}, mixins = []) { ['getFieldsValue', 'getFieldValue', 'setFieldsInitialValue', + 'getFieldInitialValue', 'getFieldsError', 'getFieldError', 'isFieldValidating', @@ -68,6 +69,7 @@ function createBaseForm(option = {}, mixins = []) { onCollectCommon(name_, action, args) { let name = name_; + let touched = false; const fieldMeta = this.fieldsStore.getFieldMeta(name); if (fieldMeta[action]) { fieldMeta[action](...args); @@ -77,6 +79,11 @@ function createBaseForm(option = {}, mixins = []) { const value = fieldMeta.getValueFromEvent ? fieldMeta.getValueFromEvent(...args) : getValueFromEvent(...args); + + if (value !== this.fieldsStore.getFieldInitialValue(name)) { + touched = true; + } + if (onValuesChange && value !== this.fieldsStore.getFieldValue(name)) { onValuesChange(this.props, set({}, name, value)); } @@ -85,7 +92,7 @@ function createBaseForm(option = {}, mixins = []) { name = nameKeyObj.name; } const field = this.fieldsStore.getField(name); - return ({ name, field: { ...field, value, touched: true }, fieldMeta }); + return ({ name, field: { ...field, value, touched }, fieldMeta }); }, onCollect(name_, action, ...args) { diff --git a/src/createFieldsStore.js b/src/createFieldsStore.js index 7db39021..6c64f783 100644 --- a/src/createFieldsStore.js +++ b/src/createFieldsStore.js @@ -70,6 +70,7 @@ class FieldsStore { const fieldMeta = this.fieldsMeta[name]; return fieldMeta && fieldMeta.initialValue; } + getValueFromFields(name, fields) { const { fieldsMeta } = this; if (fieldsMeta[name] && fieldsMeta[name].virtual) { @@ -179,6 +180,11 @@ class FieldsStore { }); } + getFieldInitialValue = (name) => { + const fieldsMeta = this.fieldsMeta; + return fieldsMeta && fieldsMeta[name] ? fieldsMeta[name].initialValue : undefined; + } + isFieldValidating = (name) => { return this.getFieldMember(name, 'validating'); } diff --git a/src/createForm.js b/src/createForm.js index a671a24e..fdeb1a55 100644 --- a/src/createForm.js +++ b/src/createForm.js @@ -10,6 +10,7 @@ export const mixin = { setFields: this.setFields, setFieldsInitialValue: this.fieldsStore.setFieldsInitialValue, getFieldDecorator: this.getFieldDecorator, + getFieldInitialValue: this.getFieldInitialValue, getFieldProps: this.getFieldProps, getFieldsError: this.fieldsStore.getFieldsError, getFieldError: this.fieldsStore.getFieldError, diff --git a/tests/touched.spec.js b/tests/touched.spec.js new file mode 100644 index 00000000..98d73f7e --- /dev/null +++ b/tests/touched.spec.js @@ -0,0 +1,76 @@ +/* eslint-disable no-undef, react/prop-types */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Simulate } from 'react-dom/test-utils'; +import createForm from '../src/createForm'; + +class Test extends React.Component { + render() { + const { getFieldProps } = this.props.form; + return (
+ +
); + } +} + +Test = createForm({ + withRef: true, +})(Test); + +describe('touched feature', () => { + let container; + let component; + let form; + + beforeEach(() => { + container = document.createElement('div'); + document.body.appendChild(container); + component = ReactDOM.render(, container); + component = component.refs.wrappedComponent; + form = component.props.form; + }); + + afterEach(() => { + ReactDOM.unmountComponentAtNode(container); + document.body.removeChild(container); + }); + + it('isFieldsTouched works', () => { + expect(form.isFieldsTouched()).toBe(false); + form.getFieldInstance('input').value = '2'; + Simulate.change(form.getFieldInstance('input')); + expect(form.isFieldsTouched()).toBe(true); + form.resetFields(); + expect(form.isFieldsTouched()).toBe(false); + }); + + it(`changing a field value back to it's initial value restores the untouched state`, () => { + const formField = form.getFieldInstance('input'); + const initialValue = form.getFieldInitialValue('input'); + + formField.value = '2'; + Simulate.change(formField); + expect(form.isFieldsTouched()).toBe(true); + formField.value = initialValue; + Simulate.change(formField); + expect(form.isFieldsTouched()).toBe(false); + }); + + it(`focus and blurring a field with validation rules without changing the value + should not cause it to be 'touched'`, () => { + const formField = form.getFieldInstance('input'); + + expect(form.isFieldsTouched()).toBe(false); + Simulate.focus(formField); + Simulate.blur(formField); + expect(form.isFieldsTouched()).toBe(false); + }); +});