apollo-form
Version:
Form state manager
270 lines (269 loc) • 9.32 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
const isEqual_1 = __importDefault(require("lodash/isEqual"));
const utils_1 = require("../utils");
const react_1 = __importDefault(require("react"));
const StateManipulator_1 = __importDefault(require("./StateManipulator"));
const emptyDepencencies = [];
const defaultState = {
errors: {},
touches: {},
isValid: true,
loading: false,
existsChanges: false,
isSubmitted: false,
focused: null,
submitCount: 0,
};
class FormManager {
constructor(props) {
this.customValidators = {};
this.timeouts = [];
this.name = props.name;
this.manager = props.manager;
this.validateHandler = props.validate;
this.onChange = props.onChange;
this.onSubmit = props.onSubmit;
this.validationSchema = props.validationSchema;
this.validateOnMount = props.validateOnMount || false;
this.resetOnSubmit = props.resetOnSubmit || false;
this.formatState = props.formatState;
this.initialState = cloneDeep_1.default(props.initialState);
this.initialErrors = cloneDeep_1.default(props.initialErrors) || {};
this.initialTouches = cloneDeep_1.default(props.initialTouches) || {};
this.manipulator = new StateManipulator_1.default(Object.assign(Object.assign({}, props), { defaultState, initialTouches: this.initialTouches, initialErrors: this.initialErrors, customValidators: this.customValidators }));
// for set default
if (!this.manager.get()) {
this.set(Object.assign(Object.assign({}, defaultState), { values: this.initialState, errors: this.initialErrors, touches: this.initialTouches }));
}
this.validate(this.validateOnMount);
const timeout = setTimeout(() => {
this.validate(this.validateOnMount);
if (props.onInit) {
props.onInit(this);
}
});
this.timeouts.push(timeout);
}
set(state) {
return this.manager.set(state);
}
get() {
let data = this.manager.get();
if (!data) {
this.manager.set(Object.assign(Object.assign({}, defaultState), { values: this.initialState, errors: this.initialErrors, touches: this.initialTouches }));
data = this.manager.get();
}
return cloneDeep_1.default(data);
}
exists() {
try {
const data = this.manager.get();
return Boolean(data);
}
catch (e) {
return false;
}
}
useState(selector = ((s) => s), dependencies = emptyDepencencies) {
const fullState = this.get();
const [state, setState] = react_1.default.useState(selector ? selector(fullState) : fullState);
react_1.default.useEffect(() => {
const nextState = selector ? selector(fullState) : fullState;
if (JSON.stringify(state) !== JSON.stringify(nextState)) {
setState(nextState);
}
return this.watch(selector, s => setState(s));
}, [selector, ...dependencies]);
return state;
}
watch(selector, handler) {
return this.manager.watch(selector, handler, (selector
? selector(this.get())
: this.get()));
}
useValue(key) {
const watcher = react_1.default.useCallback(state => {
return this.manipulator.getValue(state, key);
}, [key]);
const value = this.useState(watcher, [key]);
return value;
}
useTouched(key) {
const watcher = react_1.default.useCallback(state => {
return this.manipulator.getTouched(state, key);
}, [key]);
const value = this.useState(watcher, [key]);
return value;
}
useError(key) {
const watcher = react_1.default.useCallback(state => {
return this.manipulator.getError(state, key);
}, [key]);
const value = this.useState(watcher, [key]);
return value;
}
setValues(values) {
const prev = Object.assign({}, this.get());
const next = Object.assign(Object.assign({}, prev), { values });
const event = { type: 'all', value: next.values };
if (this.formatState) {
next.values = this.formatState({ next: next.values, prev: prev.values, event });
}
if (!isEqual_1.default(this.initialState, prev.values)) {
next.existsChanges = true;
}
else {
next.existsChanges = false;
}
this.set(next);
if (this.onChange) {
this.onChange(next.values, prev.values, this, event);
}
}
setErrors(errors) {
return this.set(Object.assign(Object.assign({}, this.get()), { errors }));
}
setTouches(touches) {
return this.set(Object.assign(Object.assign({}, this.get()), { touches }));
}
setFieldValue(key, newValue) {
let state = this.get();
const prevValues = cloneDeep_1.default(state.values);
const touched = utils_1.getDeepStatus(state.touches, key);
const event = { type: 'field', key, value: newValue };
if (!touched) {
this.manipulator.setTouched(state, key, true);
}
this.manipulator.setValue(state, key, newValue);
if (this.formatState) {
state.values = this.formatState({ next: state.values, prev: prevValues, event });
}
this.manipulator.validate(state, false);
if (!isEqual_1.default(this.initialState, state.values)) {
state.existsChanges = true;
}
else {
state.existsChanges = false;
}
this.set(state);
if (this.onChange) {
this.onChange(state.values, prevValues, this, event);
}
return state;
}
setFieldError(key, error) {
const state = this.get();
this.manipulator.setError(state, key, error);
const nextIsValid = !Boolean(utils_1.firstError(state.errors));
state.isValid = nextIsValid;
return this.set(state);
}
setFieldTouched(key, value) {
const state = this.get();
this.manipulator.setTouched(state, key, value);
state.focused = null;
return this.set(state);
}
setFieldFocused(key) {
const state = this.get();
state.focused = key;
return this.set(state);
}
setIsValid(value) {
const state = this.get();
state.isValid = value;
return this.set(state);
}
setIsSubmitted(value) {
const state = this.get();
state.isSubmitted = value;
return this.set(state);
}
setExistsChanges(value) {
const state = this.get();
state.existsChanges = value;
return this.set(state);
}
setLoading(value) {
const state = this.get();
state.loading = value;
return this.set(state);
}
validate(allTouched) {
const state = this.get();
this.manipulator.validate(state, allTouched);
this.set(state);
}
addFieldValidator(key, func) {
if (!this.customValidators[key]) {
this.customValidators[key] = func;
}
}
removeFieldValidator(key) {
delete this.customValidators[key];
}
submit() {
const state = this.get();
this.manipulator.validate(state, true);
state.isSubmitted = true;
if (this.onSubmit && state.isValid) {
state.loading = true;
state.submitCount++;
this.set(state);
return this.onSubmit(state, this)
.then(s => {
const state2 = this.get();
if (this.resetOnSubmit) {
this.manipulator.reset(state2);
}
state2.loading = false;
this.set(state2);
return s;
})
.catch((err) => {
const state2 = this.get();
state2.loading = false;
this.set(state2);
return err;
});
}
else {
this.set(state);
return Promise.resolve();
}
}
reset(getState) {
const state = this.get();
this.manipulator.reset(state, getState);
this.manipulator.validate(state, this.validateOnMount);
state.isSubmitted = false;
state.existsChanges = false;
state.responseMessage = undefined;
this.initialState = state.values;
this.set(state);
}
responseMessage(message) {
const state = this.get();
state.responseMessage = message;
this.set(state);
}
getInitialState() {
return this.initialState;
}
renewOnChange(handler) {
this.onChange = handler;
}
renewOnSubmit(handler) {
this.onSubmit = handler;
}
stopTimeouts() {
this.timeouts.forEach(clearTimeout);
this.timeouts = [];
}
}
exports.default = FormManager;