Creating and Editing Forms without Duplication in Laravel using Inertia/Vue
Here is an example how to use only one form for creating and editing a Laravel Example Model.
The ExampleController
:
public function create()
{
return Inertia::render('Example/Create');
}
public function edit(Example $example)
{
return Inertia::render('Example/Edit', compact('example'));
}
public function store(ExampleRequest $request)
{
$example = new Example();
return $this->update($request, $example);
}
public function update(ExampleRequest $request, Example $example)
{
$example->fill([
'title' => $request->input('title');
// ... what ever you need here
]);
$example->save();
return redirect(route('example.edit', ['example' => $example]));
}
The trick is to use fill and save, so we can call the update
function within the store
function, while allowing autloading the model via route-model-binding.
Now lets take a look in the Edit.vue and Create.vue. To avoid duplication, both share the same ExampleForm.vue component.
ExampleForm.vue
We send for both create and update a POST request, but for the update we use the hidden _method PUT variable. It would be possible to make an actual PUT request, but this conflicts when we send FormData. Whenever we send files, all the input is send via FormData.
In addition, I have setup notyf for a popup notification. You can choose whatever suits you best.
<template>
<form @submit.prevent="submit" >
<input v-model="form.name">
<button type="submit" :disabled="form.processing">
</form>
</template>
<script setup>
import { useForm } from '@inertiajs/vue3'
const notyf = inject('notyf');
const props = defineProps(['example', 'postRoute', '_method', 'successMessage']);
const formData = {
name: props.example.name
}
if (props._method) {
formData._method = props._method;
}
const form = useForm(formData);
function submit() {
form.post(props.postRoute, {
preserveScroll: true,
onSuccess: page => { notyf.success(props.successMessage);},
onError: errors => { Object.values(errors).forEach((value) => {
notyf.error(value);
});}
});
}
Create.vue
I am using the Ziggy library to be able to use the route helper.
<script setup lang="ts">
import ExampleForm from "./ExampleForm.vue";
</script>
<template>
<ExampleForm
:example="{}"
:post-route="route('example.store')"
success-message="Example Modelhas been created">
</ExampleForm>
</template>
Edit.vue
<script setup lang="ts">
import ExampleForm from "./ExampleForm.vue";
const props = defineProps(['example']);
</script>
<template>
<ExampleForm
:example="example"
:post-route="route('example.update', {example: example.id})"
_method="PUT"
success-message="Example Modelhas been updated">
</ExampleForm>
</template>