DEV Community

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

Posted on • Updated 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 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!! šŸ¦„ ā¤ļø

Top comments (1)

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?