react-browser-form
Version:
<div align="center"> <a href="https://deniskabana.github.io/react-browser-form/introduction" title="React Browser Form - Form management in React made simple for browsers."> <img src="https://raw.githubusercontent.com/deniskabana/react-browser-form/
113 lines (89 loc) • 4.58 kB
text/typescript
import { DataFlowState, EventSource, EventType } from "../../types";
import { hydrateDomInputs } from "../../utils/hydrateDomInputs";
import { getDomInputValue } from "../getDomInputValue";
import { hydrateFormState } from "../hydrateFormState";
import { transformValueType } from "../transformValueType";
import { validateFormState } from "../validateFormState";
export function handleChangeEvent<Schema>(dataFlowState: DataFlowState<Schema>): void {
const { options } = dataFlowState;
// 1. USER CHANGE EVENT
// --------------------------------------------------------------------------------
if (dataFlowState.event.source === EventSource.User) {
if (dataFlowState.event.type !== EventType.FormInit) {
// DEBUG: Feedback for changeReason
dataFlowState.changeReason = `Change form values programatically.\nSource: ${dataFlowState.event.source}`;
}
const eventValue = dataFlowState.event.value;
if (!eventValue) return;
// 1.1. Set form to dirty and update dirtyFields
if (!dataFlowState.isDirty) dataFlowState.setIsDirty(true);
dataFlowState.setDirtyFields(Object.keys(eventValue) as Array<keyof Schema>);
// 1.2. Populate changedData, quit if no value was provided
dataFlowState.changedData = eventValue;
// 1.3. Validate form state (validates only changedData)
validateFormState(dataFlowState);
// 1.4. Populate formState with transformed data
// TODO: Figure out a better way to do transformations
for (let key in dataFlowState.changedData) {
(dataFlowState.formState as any)[key] = transformValueType(
key as keyof Schema,
dataFlowState.changedData[key],
dataFlowState,
);
}
// 1.5. Hydrate DOM inputs from form state
hydrateDomInputs(options, dataFlowState.formState);
// 1.6. Trigger callback
dataFlowState.callbacks.onChange({ ...dataFlowState.formState });
}
// 2. FORM CHANGE EVENT
// --------------------------------------------------------------------------------
if (dataFlowState.event.source === EventSource.Form) {
const targetInput = dataFlowState.event.nativeEvent?.target as HTMLInputElement;
const fieldName = targetInput?.name;
if (!targetInput || !fieldName) return;
// 2.1. Set form to dirty and update dirtyFields
if (!dataFlowState.isDirty && targetInput && fieldName) dataFlowState.setIsDirty(true);
dataFlowState.setDirtyFields([fieldName] as Array<keyof Schema>);
// 2.2. Conditional execution and revalidation
const hasOnChangeMode = options.mode === "onChange";
const isLiveField = options.liveFields.includes(fieldName as keyof Schema);
const shouldRevalidate =
dataFlowState.errorData.errors[fieldName as keyof Schema] &&
options.revalidationStrategy === "onChange" &&
(options.mode === "onBlurUnlessError" || options.mode === "onSubmitUnlessError");
const shouldExecute = hasOnChangeMode || isLiveField || shouldRevalidate;
if (!shouldExecute) return;
// 2.3. Hydrate form state from DOM inputs
hydrateFormState(dataFlowState, [fieldName]);
// 2.4. Populate changedData with the single input value that has changed
const value = getDomInputValue(dataFlowState);
dataFlowState.changedData[fieldName as keyof Schema] = value;
// 2.5. Populate formState with transformed data
// TODO: Figure out a better way to do transformations
dataFlowState.formState[fieldName as keyof Schema] = transformValueType(
fieldName as keyof Schema,
value,
dataFlowState,
);
// 2.6. If live field changed, populate changedData with all errored fields for revalidation - live fields are often conditional / dependent
if (isLiveField) {
for (let key in dataFlowState.errorData.errors) {
dataFlowState.changedData[key] = dataFlowState.formState[key];
}
}
// 2.7. Validate form state (validates only changedData)
validateFormState(dataFlowState);
// DEBUG: Feedback for changeReason
if (hasOnChangeMode)
dataFlowState.changeReason = `Changed form state - onChange mode.\nSource: ${dataFlowState.event.source}`;
if (shouldRevalidate)
dataFlowState.changeReason = `Changed form state - error revalidation.\nSource: ${dataFlowState.event.source}`;
if (isLiveField)
dataFlowState.changeReason = `Changed form state - live field.\nSource: ${dataFlowState.event.source}`;
// 2.8. Trigger callback
if (hasOnChangeMode || isLiveField) {
dataFlowState.callbacks.onChange(dataFlowState.formState);
}
}
}