Laravel 11 Inertia Vue JS CRUD Example Tutorial

By Hardik Savani September 4, 2024 Category : Laravel

In this tutorial, I will you you step by step CRUD Application using Inertia Vue JS. we will use breeze install auth scaffold and vue js setup.

Inertia.js is a framework that allows you to build single-page applications (SPAs) using traditional server-side routing. It lets you use frontend frameworks like React, Vue, or Svelte without the need for a separate API. Instead of returning HTML, the server sends JSON data to the frontend, which Inertia then renders. This setup simplifies development by keeping the server-side and client-side code together, making it easier to manage and maintain your application.

In this example, we will install breeze and create auth scaffolding using Inertia vue js. Then we will create a posts table with title and body fields. We will create a simple CRUD operation of post module using vue js. So let's follow step by step and create a CRUD application with Vue JS.

Preview:

Step for Laravel 11 CRUD using Inertia Vue JS

  • Step 1: Install Laravel 11
  • Step 2: Create Auth using Breeze
  • Step 3: Create Migration and Model
  • Step 4: Create PostController File
  • Step 5: Create Route
  • Step 6: Update Vue Component
  • Run Laravel App

Step 1: Install Laravel 11

First of all, we need to get a fresh Laravel 11 version application using the command below because we are starting from scratch. So, open your terminal or command prompt and run the command below:

composer create-project laravel/laravel example-app

Step 2: Create Auth using Breeze

Now, in this step, we need to use the composer command to install breeze, so let's run the below command and install the below library.

composer require laravel/breeze --dev

Now, we need to create authentication using the below command. You can create basic login, register, and email verification.

Now, you need to choose "Vue with Inertia" option.

You can see below commands:

php artisan breeze:install

Now, we need to run the migration command to create the database table.

php artisan migrate

Step 3: Create Migration and Model

Here, we need to create a database migration for the posts table, and also we will create a model for the posts table.

php artisan make:migration create_posts_table

Migration:

<?php
  
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
  
return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('body');
            $table->timestamps();
        });
    }
  
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};

run migration now:

php artisan migrate

Now we will create a Post model by using the following command:

php artisan make:model Post

App/Models/Post.php

<?php
  
namespace App\Models;
  
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
  
class Post extends Model
{
    use HasFactory;
  
    protected $fillable = [
        'title', 'body'
    ];
}

Step 4: Create PostController File

Now, here we will create a PostController using artisan command. So, run the below command to create a Post CRUD application component.

php artisan make:controller PostController

now, let update the following code to the PostCotroller file.

app/Http/Controllers/PostController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Post;
use Inertia\Inertia;

class PostController extends Controller
{
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function index()
    {
        $posts = Post::all();
        return Inertia::render('Post/Index', ['posts' => $posts]);
    }

    /**
     * Write code on Method
     *
     * @return response()
     */
    public function create()
    {
        return Inertia::render('Post/Create');
    }

    /**
     * Write code on Method
     *
     * @return response()
     */
    public function store(Request $request)
    {
        $post = new Post($request->all());
        $post->save();

        return redirect()->route('posts.index');
    }

    /**
     * Write code on Method
     *
     * @return response()
     */
    public function edit(Post $post)
    {
        return Inertia::render('Post/Edit', ['post' => $post]);
    }

    /**
     * Write code on Method
     *
     * @return response()
     */
    public function update(Request $request, Post $post)
    {
      $post->update($request->all());
      return redirect()->route('posts.index');
    }

    /**
     * Write code on Method
     *
     * @return response()
     */
    public function destroy(Post $post)
    {
        $post->delete();
        return redirect()->back();
    }
}

Step 5: Create Route

In this step, we will create posts resource route in web.php file. so, let's update the file:

routes/web.php

<?php

...
use App\Http\Controllers\PostController;

Route::resource('posts', PostController::class);

Step 6: Update Vue Files

Here, we will update the following list of files for our listing page and create vue component files.

So, let's update all the files as below:

resources/js/Pages/Post/Index.vue

<script setup>
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
import { Head, Link, useForm } from '@inertiajs/vue3';

defineProps({
  posts: {
    type: Array,
    default: () => [],
  },
});

const form = useForm({});

const deletePost = (id) => {
    form.delete(`posts/${id}`);
};
</script>

<template>
    <Head title="Manage Posts" />

    <AuthenticatedLayout>
        <template #header>
            <h2 class="font-semibold text-xl text-gray-800 leading-tight">Manage Posts</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="p-6 text-gray-900">
                        <Link href="posts/create"><button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded my-3">Create New Post</button></Link>
                        <table class="table-auto w-full">
                            <thead>
                              <tr>
                                <th class="border px-4 py-2">ID</th>
                                <th class="border px-4 py-2">Title</th>
                                <th class="border px-4 py-2">Content</th>
                                <th class="border px-4 py-2" width="250px">Action</th>
                              </tr>
                              </thead>
                              <tbody>
                                <tr v-for="post in posts" :key="post.id">
                                  <td class="border px-4 py-2">{{ post.id }}</td>
                                  <td class="border px-4 py-2">{{ post.title }}</td>
                                  <td class="border px-4 py-2">{{ post.body }}</td>
                                  <td class="border px-4 py-2">
                                    <Link :href="`posts/${post.id}/edit`"><button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Edit</button></Link>
                                    <button class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded ml-2" @click="deletePost(post.id)">Delete</button>
                                  </td>
                                </tr>
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </AuthenticatedLayout>
</template>

resources/js/Pages/Post/Create.vue

<script setup>
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
import { useForm, Link } from "@inertiajs/vue3";

const form = useForm({
  title: "",
  body: "",
});

const submit = () => {
  form.post("/posts");
};
</script>

<template>
    <Head title="Manage Posts" />

    <AuthenticatedLayout>
        <template #header>
            <h2 class="font-semibold text-xl text-gray-800 leading-tight">Create Post</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="p-6 text-gray-900">
                        <Link href="/posts"><button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded my-3">Back</button></Link>
                        
                        <form @submit.prevent="submit">
                            <div class="mb-4">
                                <label 
                                    for="title" 
                                    class="block text-gray-700 text-sm font-bold mb-2">
                                    Title:</label>
                                <input 
                                    type="text" 
                                    class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" 
                                    placeholder="Enter Title" 
                                    id="title"
                                    v-model="form.title" />

                            </div>

                            <div class="mb-4">
                                <label 
                                    for="body" 
                                    class="block text-gray-700 text-sm font-bold mb-2">
                                    Body:</label>
                                <textarea 
                                    class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="body" 
                                    v-model="form.body" 
                                    placeholder="Enter Body"></textarea>
                            </div>

                            <button type="submit" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded my-3 text-white">
                                Submit
                            </button>

                        </form>

                    </div>
                </div>
            </div>
        </div>
    </AuthenticatedLayout>
</template>

resources/js/Pages/Post/Edit.vue

<script setup>
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
import { useForm, Link } from "@inertiajs/vue3";

const props = defineProps({
  post: {
    type: Object,
    default: null,
  },
});

const form = useForm({
  title: props.post.title,
  body: props.post.body,
});

const submit = () => {
  form.put(`/posts/${props.post.id}`);
};
</script>

<template>
    <Head title="Manage Posts" />

    <AuthenticatedLayout>
        <template #header>
            <h2 class="font-semibold text-xl text-gray-800 leading-tight">Edit Post</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="p-6 text-gray-900">
                        <Link href="/posts"><button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded my-3">Back</button></Link>
                        
                        <form @submit.prevent="submit">
                            <div class="mb-4">
                                <label 
                                    for="title" 
                                    class="block text-gray-700 text-sm font-bold mb-2">
                                    Title:</label>
                                <input 
                                    type="text" 
                                    class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" 
                                    placeholder="Enter Title" 
                                    id="title"
                                    v-model="form.title" />

                            </div>

                            <div class="mb-4">
                                <label 
                                    for="body" 
                                    class="block text-gray-700 text-sm font-bold mb-2">
                                    Body:</label>
                                <textarea 
                                    class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="body" 
                                    v-model="form.body" 
                                    placeholder="Enter Body"></textarea>
                            </div>

                            <button type="submit" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded my-3 text-white">
                                Submit
                            </button>

                        </form>

                    </div>
                </div>
            </div>
        </div>
    </AuthenticatedLayout>
</template>

Now, inside the AuthenticatedLayout file. we need to add link on header for posts page.

resources/js/Layouts/AuthenticatedLayout.vue

<NavLink :href="route('posts.index')" :active="route().current('posts.index')">
    Posts
</NavLink>

Run Laravel App:

All the required steps have been done, now you have to type the given below command and hit enter to run the Laravel app:

php artisan serve

Now, we need to build our application using npm command, so run the NPM command:

npm run build

Now, Go to your web browser, type the given URL and view the app output:

http://localhost:8000/

Preview:

List View:

now it works...

I hope it can help you...

Shares