Skip to content

Instantly share code, notes, and snippets.

@mattiasghodsian
Last active April 21, 2025 18:59
Show Gist options
  • Save mattiasghodsian/9b4ee07e805547aa13795dc3a28a206d to your computer and use it in GitHub Desktop.
Save mattiasghodsian/9b4ee07e805547aa13795dc3a28a206d to your computer and use it in GitHub Desktop.
Inertia.js Form Helper for Axios/API calls

Inertia.js currently lacks a built-in method for making endpoint requests to retrieve data without triggering a page reload. The following solution is adapted from mohitmamoria solution implementation.

Example

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

form.get(route('library.title'), {
    onSuccess: (response) => {
        title.value = response.title;
    }
});

Controller

public function example(Request $request): JsonResponse
{
    return response()->json([
        'title' => 'hello world'
    ]);
}
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 = {}) => {
// 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());
// Configure request based on method
const config = {
method: method.toLowerCase(),
url: url,
headers: {
...options.headers,
'Content-Type': hasFiles(data) ? 'multipart/form-data' : 'application/json',
},
onUploadProgress: (event) => {
form.progress = event;
if (options.onProgress) {
options.onProgress(event);
}
}
};
// Handle GET requests differently
if (method.toLowerCase() === 'get') {
config.params = data;
} else {
config.data = data;
}
// Make the request
axios(config)
.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;
})
.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);
}
})
.finally(() => {
form.processing = false;
form.progress = null;
if (options.onFinish) {
options.onFinish();
}
});
},
};
return new Proxy(form, {
get: (target, prop, receiver) => {
return Object.keys(overriders).indexOf(prop) < 0
? target[prop]
: overriders[prop](receiver);
},
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment