Skip to content

Instantly share code, notes, and snippets.

@mohitmamoria
Last active June 25, 2024 11:07
Show Gist options
  • Save mohitmamoria/91da6f30d9610b211248225c9e52bebe to your computer and use it in GitHub Desktop.
Save mohitmamoria/91da6f30d9610b211248225c9e52bebe to your computer and use it in GitHub Desktop.
Inertia.js Form Helper for Axios/API calls

Inertia.js ships with a fantastic form helper but it falls short when also using API/Axios calls in your project.

Here's a composable, built on top of the Inertia's form helper that hooks into it to replace the API calls with Axios.

To use, just replace useForm with useAPIForm.

const form = useAPIForm({
    title: '',
});

Everything else just works!

import { useForm } from '@inertiajs/vue3';
import cloneDeep from 'lodash.clonedeep';
export function hasFiles(data) {
return (
data instanceof File ||
data instanceof Blob ||
(data instanceof FileList && data.length > 0) ||
(data instanceof FormData && Array.from(data.values()).some((value) => hasFiles(value))) ||
(typeof data === 'object' && data !== null && Object.values(data).some((value) => hasFiles(value)))
);
}
export function useAPIForm(rememberKeyOrData, maybeData = null) {
const form = useForm(rememberKeyOrData, maybeData);
let transform = (data) => data;
let recentlySuccessfulTimeoutId = null;
const overriders = {
transform: (receiver) => (callback) => {
transform = callback;
return receiver;
},
submit:
(receiver) =>
(method, url, options = {}) => {
// TODO: cancelToken system
// BEFORE
form.wasSuccessful = false;
form.recentlySuccessful = false;
form.clearErrors();
clearTimeout(recentlySuccessfulTimeoutId);
if (options.onBefore) {
options.onBefore();
}
// START
form.processing = true;
if (options.onStart) {
options.onStart();
}
// MAKING THE CALL
const data = transform(form.data());
axios[method](url, data, {
headers: {
'Content-Type': hasFiles(data) ? 'multipart/form-data' : 'application/json',
},
onUploadProgress: (event) => {
form.progress = event;
if (options.onProgress) {
options.onProgress(event);
}
},
})
// ON SUCCESS
.then((response) => {
form.processing = false;
form.progress = null;
form.clearErrors();
form.wasSuccessful = true;
form.recentlySuccessful = true;
recentlySuccessfulTimeoutId = setTimeout(() => (form.recentlySuccessful = false), 2000);
if (options.onSuccess) {
options.onSuccess(response.data);
}
form.defaults(cloneDeep(form.data()));
form.isDirty = false;
})
// ON ERROR
.catch((error) => {
form.processing = false;
form.progress = null;
// Set validation errors
form.clearErrors();
if (error.response?.status === 422) {
Object.keys(error.response.data.errors).forEach((key) => {
form.setError(key, error.response.data.errors[key][0]);
});
}
if (options.onError) {
options.onError(error);
}
})
// ON FINISH
.finally(() => {
form.processing = false;
form.progress = null;
if (options.onFinish) {
options.onFinish();
}
});
},
};
return new Proxy(form, {
get: (target, prop, receiver) => {
// If not overridden:
if (Object.keys(overriders).indexOf(prop) < 0) {
return target[prop];
}
return overriders[prop](receiver);
},
});
}
@yourjhay
Copy link

You have similar for react ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment