DEV Community

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

Posted on • Edited on

26

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 EventController
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!! 🦄 ❤️

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (2)

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

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more