accounts-frontend/src/components/ui/form/Form.jsx

130 lines
3.4 KiB
React
Raw Normal View History

2016-05-02 12:45:42 +05:30
import React, { Component, PropTypes } from 'react';
import classNames from 'classnames';
import FormModel from './FormModel';
2016-05-02 12:45:42 +05:30
import styles from './form.scss';
export default class Form extends Component {
static displayName = 'Form';
static propTypes = {
id: PropTypes.string, // and id, that uniquely identifies form contents
isLoading: PropTypes.bool,
form: PropTypes.instanceOf(FormModel),
2016-05-02 12:45:42 +05:30
onSubmit: PropTypes.func,
onInvalid: PropTypes.func,
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
])
};
static defaultProps = {
id: 'default',
isLoading: false,
onSubmit() {},
onInvalid() {}
};
state = {
2016-05-28 01:34:17 +05:30
isTouched: false,
isLoading: this.props.isLoading || false
2016-05-02 12:45:42 +05:30
};
2016-05-28 01:34:17 +05:30
componentWillMount() {
if (this.props.form) {
this.props.form.addLoadingListener(this.onLoading);
}
}
2016-05-02 12:45:42 +05:30
componentWillReceiveProps(nextProps) {
if (nextProps.id !== this.props.id) {
this.setState({
isTouched: false
});
}
2016-05-28 01:34:17 +05:30
if (typeof nextProps.isLoading !== 'undefined') {
this.setState({
isLoading: nextProps.isLoading
});
}
if (nextProps.form && this.props.form && nextProps.form !== this.props.form) {
this.props.form.removeLoadingListener(this.onLoading);
nextProps.form.addLoadingListener(this.onLoading);
2016-05-28 01:34:17 +05:30
}
}
componentWillUnmount() {
if (this.props.form) {
this.props.form.removeLoadingListener(this.onLoading);
}
2016-05-02 12:45:42 +05:30
}
render() {
2016-05-28 01:34:17 +05:30
const {isLoading} = this.state;
2016-05-02 12:45:42 +05:30
return (
<form
className={classNames(
styles.form,
{
[styles.isFormLoading]: isLoading,
[styles.formTouched]: this.state.isTouched
}
)}
onSubmit={this.onFormSubmit}
noValidate
>
{this.props.children}
</form>
);
}
onFormSubmit = (event) => {
event.preventDefault();
if (!this.state.isTouched) {
this.setState({
isTouched: true
});
}
const form = event.currentTarget;
if (form.checkValidity()) {
this.props.onSubmit();
} else {
const invalidEls = form.querySelectorAll(':invalid');
const errors = {};
invalidEls[0].focus(); // focus on first error
Array.from(invalidEls).reduce((errors, el) => {
if (!el.name) {
console.warn('Found an element without name', el);
return errors;
}
let errorMessage = el.validationMessage;
if (el.validity.valueMissing) {
errorMessage = `error.${el.name}_required`;
} else if (el.validity.typeMismatch) {
errorMessage = `error.${el.name}_invalid`;
}
errors[el.name] = errorMessage;
2016-05-02 12:45:42 +05:30
return errors;
}, errors);
2016-05-02 12:45:42 +05:30
this.props.form && this.props.form.setErrors(errors);
this.props.onInvalid(errors);
2016-05-02 12:45:42 +05:30
}
};
2016-05-28 01:34:17 +05:30
onLoading = (isLoading) => this.setState({isLoading});
2016-05-02 12:45:42 +05:30
}