DEV Community

Cover image for Laravel 11 + Inertia JS (VUE) CRUD Example: Part 2
Snehal Rajeev Moon
Snehal Rajeev Moon

Posted on • Edited on

Laravel 11 + Inertia JS (VUE) CRUD Example: Part 2

Hello Artisan,

In the previous blog post, we saw how to set laravel + inertia js project to create a crud operation. If you haven't read it yet, then you can read it here Laravel 11 + Inertia JS (VUE) CRUD Example: Part 1
and configure a basic setup. In this part 2 series, we will build the frontend and backend logic and see how easily inertia seamlessly communicates with the laravel.

Step 1: Create an Event Controller and add the routes in web.php

php artisan make:controller EventManagementController 
Enter fullscreen mode Exit fullscreen mode

This route will used to create, read, update, delete events.

// web.php Route::get('/event', [EventManagementController::class, 'index']) ->name('event.index'); Route::get('/event/create', [EventManagementController::class, 'create']) ->name('event.create'); Route::post('/event/create', [EventManagementController::class, 'store']) ->name('event.store'); Route::get('/event/{event}', [EventManagementController::class, 'show']) ->name('event.show'); Route::get('/event/{event}/edit', [EventManagementController::class, 'edit']) ->name('event.edit'); Route::put('/event/{event}/update', [EventManagementController::class, 'update']) ->name('event.update'); Route::delete('/event/{event}/delete', [EventManagementController::class, 'delete']) ->name('event.delete'); 
Enter fullscreen mode Exit fullscreen mode

Step 2: Create a frontend design to create an event using Inertia.

  • Create a new folder and name it EventManagement in this given path resources\js\Pages and within that folder create a vue component as Create.vue and add the below code in that component.
<script setup> import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout.vue"; import { Head, useForm } from "@inertiajs/vue3"; import VueDatePicker from "@vuepic/vue-datepicker"; const form = useForm({ name: "", location: "", startDate: "", endDate: "", }); const save = () => { form.post(route("event.store"), { onFinish: () => form.reset(), }); }; </script>  <template> <Head title="Event Management" /> <AuthenticatedLayout> <template #header> <h2 class="font-semibold text-xl text-gray-800 leading-tight"> Create Event </h2>  </template>  <div class="p-12"> <div class="max-w-7xl mx-auto sm:px-6 lg:px-8"> <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg"> <form @submit.prevent="save"> <div class="space-y-12 p-12"> <div class="border-b border-gray-900/10 pb-12"> <h2 class="text-base font-semibold leading-7 text-gray-900" > Event </h2>  <p class="mt-1 text-sm leading-6 text-gray-600"> Add event details here </p>  <div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6" > <div class="sm:col-span-3"> <label for="name" class="block text-sm font-medium leading-6 text-gray-900" >Event name</label  > <div class="mt-2"> <input type="text" v-model="form.name" id="name" autocomplete="event name" class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" /> </div>  </div>  <div class="sm:col-span-3"> <label for="location" class="block text-sm font-medium leading-6 text-gray-900" >Location</label  > <div class="mt-2"> <input type="text" v-model="form.location" id="location" autocomplete="location" class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" /> </div>  </div>  <div class="sm:col-span-3"> <label for="start-date" class="block text-sm font-medium leading-6 text-gray-900" >Start Date</label  > <VueDatePicker v-model="form.startDate" /> </div>  <div class="sm:col-span-3"> <label for="end-date" class="block text-sm font-medium leading-6 text-gray-900" >End date</label  > <VueDatePicker v-model="form.endDate" /> </div>  </div>  </div>  <div class="mt-6 flex items-center justify-end gap-x-6" > <button type="button" class="text-sm font-semibold leading-6 text-gray-900" > Cancel </button>  <button type="submit" class="rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600" > Save </button>  </div>  </div>  </form>  </div>  </div>  </div>  </AuthenticatedLayout> </template> 
Enter fullscreen mode Exit fullscreen mode
  • Add the backend code to EventController in the store method.
public function store(Request $request) { $params = $request->all(); $data = [ 'name' => $params['name'], 'from_datetime' => $params['startDate'], 'to_datetime' => $params['endDate'], 'location' => $params['location'], ]; Event::create($data); return redirect()->route('event.index'); } 
Enter fullscreen mode Exit fullscreen mode

Step 3: Create a listing page to show the events. Create Index.vue component and add the code below.

<script setup> import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout.vue"; import { Head, Link, useForm } from "@inertiajs/vue3"; import DangerButton from "@/Components/DangerButton.vue"; import moment from "moment-js"; defineProps({ events: { type: Array, }, }); const form = useForm({}); const deleteEvent = (id) => { if (confirm("Are you sure you want to move this to trash")) { form.delete(route("event.delete", { id: id }), { preserveScroll: true, }); } }; const formatDate = (date) => { return moment(date).format("MM/DD/YYYY hh:mm"); }; </script>  <template> <Head title="Event Management" /> <AuthenticatedLayout> <template #header> <h2 class="font-semibold text-xl text-gray-800 leading-tight"> Event Management </h2>  </template>  <div class="py-12"> <div class="max-w-7xl mx-auto sm:px-6 lg:px-8"> <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg"> <div class="flex justify-between"> <div class="p-6 text-gray-900">List of events</div>  <div class="my-auto px-5"> <Link :href="route('event.create')" class="p-3 rounded my-auto text-white bg-blue-500" > Create Event </Link>  </div>  </div>  <div class="flex flex-col p-6"> <div class="overflow-x-auto sm:-mx-6 lg:-mx-8"> <div class="inline-block min-w-full py-2 sm:px-6 lg:px-8" > <div class="overflow-hidden"> <table class="min-w-full border rounded text-left text-sm font-light text-surface dark:text-white" > <thead class="border-b border-neutral-200 font-medium dark:border-white/10" > <tr> <th scope="col" class="px-6 py-4" > # </th>  <th scope="col" class="px-6 py-4" > Event Name </th>  <th scope="col" class="px-6 py-4" > Location </th>  <th scope="col" class="px-6 py-4" > Start Date </th>  <th scope="col" class="px-6 py-4" > End Date </th>  <th scope="col" class="px-6 py-4" > Action </th>  </tr>  </thead>  <tbody> <tr v-for="(event, index) in events" :key="index" class="border-b border-neutral-200 dark:border-white/10" > <td class="whitespace-nowrap px-6 py-4" > {{ index + 1 }} </td>  <td class="whitespace-nowrap px-6 py-4" > {{ event.name }} </td>  <td class="whitespace-nowrap px-6 py-4" > {{ event.location }} </td>  <td class="whitespace-nowrap px-6 py-4" > {{ formatDate( event.from_datetime ) }} </td>  <td class="whitespace-nowrap px-6 py-4" > {{ formatDate( event.to_datetime ) }} </td>  <td class="whitespace-nowrap px-6 py-4" > <Link :href=" route( 'event.show', [event.id] ) " class="p-3 rounded my-auto text-white bg-green-600" > View </Link>  <Link :href=" route( 'event.edit', { id: event.id } ) " class="ml-2 p-3 rounded my-auto text-white bg-blue-500" > Edit </Link>  <DangerButton class="ml-2 py-3 rounded my-auto text-white bg-red-500" @click=" deleteEvent( event.id ) " > Delete </DangerButton>  </td>  </tr>  </tbody>  </table>  </div>  </div>  </div>  </div>  </div>  </div>  </div>  </AuthenticatedLayout> </template> 
Enter fullscreen mode Exit fullscreen mode
  • Backend code to view all the events
/** * Show the all the event details */ public function index() { return Inertia::render('EventManagement/Index', [ 'events' => Event::get() ]); } 
Enter fullscreen mode Exit fullscreen mode

Step 4: Create a view page to show the event details. Create View.vue component and add the code below.

<script setup> import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout.vue"; import moment from "moment-js"; import { Link } from "@inertiajs/vue3"; const props = defineProps({ event: Object, }); const formatDate = (date) => { return moment(date).format("MM/DD/YYYY hh:mm"); }; </script> <template> <Head :title="props.event.name" /> <AuthenticatedLayout> <div class="py-12"> <div class="max-w-7xl mx-auto sm:px-6 lg:px-8 space-y-6"> <Link class="py-3 px-5 m-2 rounded bg-blue-600 text-white float-end" :href="route('event.index')" >Back</Link  > <div class="p-12 px-3 m-auto rounded-lg"> <div class="mt-12 bg-white py-5 px-3 rounded-lg"> <h1 class="text-2xl font-bold"> {{ props.event.name }} </h1>  <div> {{ props.event.location }} </div>  <div class="text-sm"> {{ formatDate(props.event.from_datetime) }} - {{ formatDate(props.event.to_datetime) }} </div>  </div>  </div>  </div>  </div>  </AuthenticatedLayout> </template> 
Enter fullscreen mode Exit fullscreen mode

Step 5: Create an edit page to edit the event. Create Edit.vue component and add the code below.

<script setup> import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout.vue"; import { Head, useForm, usePage } from "@inertiajs/vue3"; import VueDatePicker from "@vuepic/vue-datepicker"; import PrimaryButton from "@/Components/PrimaryButton.vue"; const props = defineProps(["event"]); const form = useForm({ id: props.event.id, name: props.event.name, location: props.event.location, startDate: props.event.from_datetime, endDate: props.event.to_datetime, }); const update = () => { form.put(route("event.update", props.event.id)); }; </script>  <template> <Head title="Event Management" /> <AuthenticatedLayout> <template #header> <h2 class="font-semibold text-xl text-gray-800 leading-tight"> Edit Event </h2>  </template>  <div class="p-12"> <div class="max-w-7xl mx-auto sm:px-6 lg:px-8"> <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg"> <form @submit.prevent="update"> <div class="space-y-12 p-12"> <div class="border-b border-gray-900/10 pb-12"> <h2 class="text-base font-semibold leading-7 text-gray-900" > Event </h2>  <p class="mt-1 text-sm leading-6 text-gray-600"> Update the event details here </p>  <div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6" > <div class="sm:col-span-3"> <label for="name" class="block text-sm font-medium leading-6 text-gray-900" >Event name</label  > <div class="mt-2"> <input type="text" v-model="form.name" id="name" autocomplete="event name" class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" /> </div>  </div>  <div class="sm:col-span-3"> <label for="location" class="block text-sm font-medium leading-6 text-gray-900" >Location</label  > <div class="mt-2"> <input type="text" v-model="form.location" id="location" autocomplete="location" class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" /> </div>  </div>  <div class="sm:col-span-3"> <label for="start-date" class="block text-sm font-medium leading-6 text-gray-900" >Start Date</label  > <VueDatePicker v-model="form.startDate" /> </div>  <div class="sm:col-span-3"> <label for="end-date" class="block text-sm font-medium leading-6 text-gray-900" >End date</label  > <VueDatePicker v-model="form.endDate" /> </div>  </div>  </div>  <div class="mt-6 flex items-center justify-end gap-x-6" > <button type="button" class="text-sm font-semibold leading-6 text-gray-900" > Cancel </button>  <PrimaryButton class="bg-indigo-800 hover:bg-blue-500" >Save</PrimaryButton  > </div>  </div>  </form>  </div>  </div>  </div>  </AuthenticatedLayout> </template> 
Enter fullscreen mode Exit fullscreen mode
  • Add this backend code for show create event page, show event, edit, update, and delete an event.
 /** * Show the form for creating a new event. */ public function create() { return Inertia::render('EventManagement/Create'); } /** * Show the event details */ public function show(Event $event) { return Inertia::render( 'EventManagement/View', [ 'event' => $event ] ); } /** * Show the form for editing the specified resource. */ public function edit(Event $event) { return Inertia::render( 'EventManagement/Edit', [ 'event' => $event ] ); } /** * Update the event */ public function update(Request $request, Event $event) { $params = $request->all(); $data = [ 'name' => $params['name'], 'from_datetime' => $params['startDate'], 'to_datetime' => $params['endDate'], 'location' => $params['location'], ]; $event->update($data); return redirect()->route('event.index'); } /** * Delete event */ public function delete(Event $event) { $event->delete(); return redirect()->back(); } 
Enter fullscreen mode Exit fullscreen mode

You can download the code from the github repository here.
Event Management Github

Happy Coding!!!
Happy Reading!! 🦄 ❤️

Top comments (4)

Collapse
 
__7b83022 profile image
Алексей Дементьев

Если у Вас EventController, откуда в маршрутах EventManagementControlle?

Collapse
 
snehalkadwe profile image
Snehal Rajeev Moon

@__7b83022 Good catch! That was a typo — I’ve corrected it. Appreciate you pointing it out!

Collapse
 
cbrghton profile image
Brighton Saldaña

Hi! If I want to edit the resource in the same view of the index, like using a modal, how I can get the data?, I try with form.get but Inertia tells me that I need an Inertia Response, I understand that is using a redirect but I can use a simple JSON response? or do I need to change the process?

Collapse
 
bytefroze profile image
Putra Fajar Hasanuddin

Something like this

on vue

function handleSave() {
form.patch(route('space.update', props.space.id), {
onSuccess: () => {
emit('close')
},
})
}

on laravel

return redirect()->back()

Hope u got the idea