react-form-with-constraints
Version:
Simple form validation for React
100 lines (99 loc) • 3.45 kB
JavaScript
import * as React from 'react';
import { instanceOf } from 'prop-types';
import { assert } from './assert';
import { FieldFeedbacks } from './FieldFeedbacks';
import { FormWithConstraints } from './FormWithConstraints';
import { withValidateFieldEventEmitter } from './withValidateFieldEventEmitter';
export var Status;
(function (Status) {
Status[Status["None"] = 0] = "None";
Status[Status["Pending"] = 1] = "Pending";
Status[Status["Rejected"] = 2] = "Rejected";
Status[Status["Resolved"] = 3] = "Resolved";
})(Status || (Status = {}));
class AsyncComponent extends React.PureComponent {
}
export class Async extends withValidateFieldEventEmitter(AsyncComponent) {
constructor() {
super(...arguments);
this.state = {
status: Status.None
};
this.validate = (input) => {
const { form, fieldFeedbacks } = this.context;
let validations;
const field = form.fieldsStore.getField(input.name);
if ((fieldFeedbacks.props.stop === 'first' && field.hasFeedbacks(fieldFeedbacks.key)) ||
(fieldFeedbacks.props.stop === 'first-error' && field.hasErrors(fieldFeedbacks.key)) ||
(fieldFeedbacks.props.stop === 'first-warning' && field.hasWarnings(fieldFeedbacks.key)) ||
(fieldFeedbacks.props.stop === 'first-info' && field.hasInfos(fieldFeedbacks.key))) {
this.setState({ status: Status.None });
}
else {
validations = this._validate(input);
}
return validations;
};
}
getChildContext() {
return {
async: this
};
}
componentDidMount() {
this.context.fieldFeedbacks.addValidateFieldEventListener(this.validate);
}
componentWillUnmount() {
this.context.fieldFeedbacks.removeValidateFieldEventListener(this.validate);
}
async setStateSync(state) {
return new Promise(resolve => {
this.setState(state, resolve);
});
}
async _validate(input) {
let state = {
status: Status.Pending
};
this.setState(state);
try {
const value = await this.props.promise(input.value);
state = { status: Status.Resolved, value };
}
catch (e) {
state = { status: Status.Rejected, value: e };
}
await this.setStateSync(state);
return this.emitValidateFieldEvent(input);
}
render() {
const { props, state } = this;
let element = null;
switch (state.status) {
case Status.None:
break;
case Status.Pending:
if (props.pending)
element = props.pending;
break;
case Status.Resolved:
if (props.then)
element = props.then(state.value);
break;
case Status.Rejected:
if (props.catch)
element = props.catch(state.value);
break;
default:
assert(false, `Unknown status: '${state.status}'`);
}
return element;
}
}
Async.contextTypes = {
form: instanceOf(FormWithConstraints).isRequired,
fieldFeedbacks: instanceOf(FieldFeedbacks).isRequired
};
Async.childContextTypes = {
async: instanceOf(Async).isRequired
};