| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- import { computed, isReactive, reactive, toRaw, watch } from "vue";
- import isEqual from "fast-deep-equal";
- export const useForm = (initialFormValue) => {
- const form = reactive(deepClone(initialFormValue));
- let originalForm = deepClone(initialFormValue);
- const updatedFields = reactive({});
- const getUpdatedFields = computed(() => {
- return updatedFields;
- });
- const hasUpdatedFields = computed(() => {
- return Object.keys(updatedFields).length > 0;
- });
- const getFormAsFormData = () => {
- const formData = new FormData();
- buildFormData(formData, form);
- return formData;
- };
- const getUpdatedFieldsAsFormData = (spoofMethod = null) => {
- const formData = new FormData();
- buildFormData(formData, updatedFields);
- if (spoofMethod) {
- formData.append("_method", spoofMethod.toUpperCase());
- }
- return formData;
- };
- const resetUpdateForm = () => {
- const newFormState = deepClone(originalForm);
- Object.keys(form).forEach((key) => delete form[key]);
- Object.assign(form, newFormState);
- };
- const setUpdateFormAsOriginal = () => {
- originalForm = deepClone(toRaw(form));
- };
- watch(
- form,
- (newValue) => {
- const changes = diff(toRaw(newValue), originalForm);
- Object.keys(updatedFields).forEach((key) => delete updatedFields[key]);
- Object.assign(updatedFields, changes);
- },
- { deep: true },
- );
- return {
- form,
- getUpdatedFields,
- hasUpdatedFields,
- getFormAsFormData,
- getUpdatedFieldsAsFormData,
- resetUpdateForm,
- setUpdateFormAsOriginal,
- };
- };
- const buildFormData = (formData, data, parentKey = "") => {
- if (data === undefined) {
- return;
- }
- if (data == null) {
- formData.append(parentKey, null);
- return;
- }
- if (Array.isArray(data)) {
- data.forEach((value, index) => {
- buildFormData(formData, value, `${parentKey}[${index}]`);
- });
- return;
- }
- if (
- typeof data === "object" &&
- !(data instanceof File) &&
- !(data instanceof Date)
- ) {
- Object.keys(data).forEach((key) => {
- const propName = parentKey ? `${parentKey}[${key}]` : key;
- buildFormData(formData, data[key], propName);
- });
- return;
- }
- let valueToAppend = data;
- if (data instanceof Date) {
- valueToAppend = data.toISOString().slice(0, 19).replace("T", " ");
- }
- formData.append(parentKey, valueToAppend);
- }
- const deepClone = (obj) => {
- if (obj && isReactive(obj)) {
- obj = toRaw(obj);
- }
- if (typeof structuredClone === "function") {
- try {
- return structuredClone(obj);
- } catch (e) {
- console.warn(
- "structuredClone not supported, using JSON methods instead: " + e,
- );
- }
- }
- return JSON.parse(JSON.stringify(obj));
- }
- const diff = (currentObj, baseObj) => {
- const changes = {};
- const currentKeys = Object.keys(currentObj);
- const baseKeys = Object.keys(baseObj);
- for (const key of currentKeys) {
- const currentValue = currentObj[key];
- const baseValue = baseObj[key];
- if (!isEqual(currentValue, baseValue)) {
- if (
- currentValue &&
- typeof currentValue === "object" &&
- !Array.isArray(currentValue) &&
- baseValue &&
- typeof baseValue === "object" &&
- !Array.isArray(baseValue)
- ) {
- const nestedChanges = diff(currentValue, baseValue);
- if (Object.keys(nestedChanges).length > 0) {
- changes[key] = nestedChanges;
- }
- } else {
- changes[key] = deepClone(currentValue);
- }
- }
- }
- for (const key of baseKeys) {
- if (!Object.prototype.hasOwnProperty.call(currentObj, key)) {
- changes[key] = null;
- }
- }
- return changes;
- }
|