From aa45b0b1e080b4208be5b8f63fa82d527dd2ea2a Mon Sep 17 00:00:00 2001 From: Michael Mueller Date: Fri, 20 Jan 2017 17:50:38 +0100 Subject: [PATCH] externalized common code and fixed revalidation for expense type typeahead --- src/common/ui/formHelpers.ts | 0 src/common/ui/forms.ts | 35 +++++++++++++++++++++ src/main/BillsEditorComponent.tsx | 46 +++++----------------------- src/main/ExpensesEditorComponent.tsx | 45 ++++++--------------------- 4 files changed, 52 insertions(+), 74 deletions(-) delete mode 100644 src/common/ui/formHelpers.ts create mode 100644 src/common/ui/forms.ts diff --git a/src/common/ui/formHelpers.ts b/src/common/ui/formHelpers.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/common/ui/forms.ts b/src/common/ui/forms.ts new file mode 100644 index 0000000..2f96969 --- /dev/null +++ b/src/common/ui/forms.ts @@ -0,0 +1,35 @@ +import * as ReactDOM from 'react-dom' + +export function addFormValidation(inputs: any[], revalidate: (input: any) => void) { + for (let input of inputs) { + input.addEventListener('input', event => revalidate(event.target)) + + input.addEventListener('invalid', (event) => { + const input: any = event.target; + input.closest('.form-group').classList.add('has-error') + }) + } +} + +export function resetFormValidationErrors(inputs: any[]) { + inputs.forEach(input => input.closest('.form-group') !.classList.remove('has-error')) +} + +export function getInputs(component) { + return [...ReactDOM.findDOMNode(component).querySelectorAll('input,textarea')] +} + +export function revalidateInput(input: any) { + input.closest('.form-group').classList.remove('has-error') + setTimeout(() => input.checkValidity()) +} + +export function enableTypeaheadFeatures(typeahead: any, name: string, required: boolean) { + const typeaheadInput = + ReactDOM.findDOMNode(typeahead.getInstance()).querySelector(`input[name=${name}]`) + typeaheadInput.setAttribute('id', name) + + if (required) { + typeaheadInput.setAttribute('required', 'true') + } +} diff --git a/src/main/BillsEditorComponent.tsx b/src/main/BillsEditorComponent.tsx index ff9c987..c0c57da 100644 --- a/src/main/BillsEditorComponent.tsx +++ b/src/main/BillsEditorComponent.tsx @@ -13,6 +13,7 @@ import { listBillTypes, getBillTypeById, createBillType } from '../common/servic import { listCustomers, createCustomer, getCustomerById, deleteCustomerById } from '../common/services/customersService' import t from '../common/helpers/i18n' import { numberFormatterDb, numberFormatterView, dateFormatterView, dateFormatterDb, getFilename } from '../common/ui/formatters' +import { enableTypeaheadFeatures, getInputs, resetFormValidationErrors, addFormValidation, revalidateInput } from '../common/ui/forms' import Textarea from 'react-textarea-autosize' const Datetime = require('react-datetime') @@ -71,7 +72,7 @@ export default class BillsEditorComponent extends React.Component { this.fetchTypeaheadData() process.nextTick(() => this.refs.invoice.focus()) this.dragCounter = 0 - this.resetFormValidationErrors() + resetFormValidationErrors(getInputs(this)) } getDefaultState(): State { @@ -459,7 +460,6 @@ export default class BillsEditorComponent extends React.Component { newSelectionPrefix={t('Kunden anlegen: ')} paginationText={t('Mehr anzeigen')} maxResults={20} - tabIndex={1} /> { ) } - addFormValidation() { - for (let input of this.getInputs()) { - input.addEventListener('input', event => this.revalidate(event.target)) - - input.addEventListener('invalid', (event) => { - const input: any = event.target; - input.closest('.form-group').classList.add('has-error') - }) - } - } - - resetFormValidationErrors() { - this.getInputs().forEach(input => input.closest('.form-group') !.classList.remove('has-error')) - } - - getInputs() { - return [...ReactDOM.findDOMNode(this).querySelectorAll('input,textarea')] - } - revalidate(input) { - this.state.isDirty = true - input.closest('.form-group').classList.remove('has-error') - setTimeout(() => input.checkValidity()) - } - - enableTypeaheadFeatures(typeahead: any, name: string, required: boolean) { - const typeaheadInput = - ReactDOM.findDOMNode(typeahead.getInstance()).querySelector(`input[name=${name}]`) - typeaheadInput.setAttribute('id', name) - - if (required) { - typeaheadInput.setAttribute('required', 'true') - } + this.state.isDirty = true // manipulate directly to prevent endless loop + revalidateInput(input) } componentDidMount() { - this.addFormValidation() - this.enableTypeaheadFeatures(this.refs.customerTypeahead, 'customer', true) - this.enableTypeaheadFeatures(this.refs.billTypeTypeahead, 'billType', false) + addFormValidation(getInputs(this), this.revalidate.bind(this)) + enableTypeaheadFeatures(this.refs.customerTypeahead, 'customer', true) + enableTypeaheadFeatures(this.refs.billTypeTypeahead, 'billType', false) } componentWillReceiveProps(nextProps: Props) { @@ -647,7 +617,7 @@ export default class BillsEditorComponent extends React.Component { if (this.state.isDirty && !confirm(t('Möchtest du die Änderungen verwerfen?'))) return - this.resetFormValidationErrors() + resetFormValidationErrors(getInputs(this)) if (isNew) { this.resetState() diff --git a/src/main/ExpensesEditorComponent.tsx b/src/main/ExpensesEditorComponent.tsx index 1ede166..72bb3d0 100644 --- a/src/main/ExpensesEditorComponent.tsx +++ b/src/main/ExpensesEditorComponent.tsx @@ -9,6 +9,7 @@ import t from '../common/helpers/i18n' import { numberFormatterDb, numberFormatterView, dateFormatterView, dateFormatterDb } from '../common/ui/formatters' import { stringIsEmpty } from '../common/helpers/text' import { getNetAmount, getVatAmount, getPreTaxAmount, hasDecimals } from '../common/helpers/math' +import { enableTypeaheadFeatures, getInputs, resetFormValidationErrors, addFormValidation, revalidateInput } from '../common/ui/forms' import Textarea from 'react-textarea-autosize' const Datetime = require('react-datetime') @@ -55,7 +56,7 @@ export default class ExpensesEditorComponent extends React.Component this.setState(this.getDefaultState()) this.refs.expenseTypeTypeahead.getInstance().clear() this.fetchTypeaheadData() - this.resetFormValidationErrors() + resetFormValidationErrors(getInputs(this)) } getDefaultState(): State { @@ -203,6 +204,8 @@ export default class ExpensesEditorComponent extends React.Component } else { this.setState({ selectedExpenseType: selected }) } + + this.revalidate(ReactDOM.findDOMNode(this.refs.expenseTypeTypeahead.getInstance()).querySelector('input[name=expenseType]')) } render() { @@ -381,44 +384,14 @@ export default class ExpensesEditorComponent extends React.Component ) } - addFormValidation() { - for (let input of this.getInputs()) { - input.addEventListener('input', event => this.revalidate(event.target)) - - input.addEventListener('invalid', (event) => { - const input: any = event.target; - input.closest('.form-group').classList.add('has-error') - }) - } - } - - resetFormValidationErrors() { - this.getInputs().forEach(input => input.closest('.form-group') !.classList.remove('has-error')) - } - - getInputs() { - return [...ReactDOM.findDOMNode(this).querySelectorAll('input,textarea')] - } - revalidate(input) { - this.state.isDirty = true - input.closest('.form-group').classList.remove('has-error') - setTimeout(() => input.checkValidity()) - } - - enableTypeaheadFeatures(typeahead: any, name: string, required: boolean) { - const typeaheadInput = - ReactDOM.findDOMNode(typeahead.getInstance()).querySelector(`input[name=${name}]`) - typeaheadInput.setAttribute('id', name) - - if (required) { - typeaheadInput.setAttribute('required', 'true') - } + this.state.isDirty = true // manipulate directly to prevent endless loop + revalidateInput(input) } componentDidMount() { - this.addFormValidation() - this.enableTypeaheadFeatures(this.refs.expenseTypeTypeahead, 'expenseType', true) + addFormValidation(getInputs(this), this.revalidate.bind(this)) + enableTypeaheadFeatures(this.refs.expenseTypeTypeahead, 'expenseType', true) } componentWillReceiveProps(nextProps: Props) { @@ -427,7 +400,7 @@ export default class ExpensesEditorComponent extends React.Component if (this.state.isDirty && !confirm(t('Möchtest du die Änderungen verwerfen?'))) return - this.resetFormValidationErrors() + resetFormValidationErrors(getInputs(this)) if (isNew) { this.resetState()