Vivek Mistry đź‘‹

I’m a Certified Senior Laravel Developer with 6+ years of experience , specializing in building robust APIs and admin panels, frontend templates converting them into fully functional web applications.

Book A Call
  • 23 Apr, 2025
  • 381 Views
  • Laravel - Vue - Explore V 1.0.0

Laravel - Vue - Basic CRUD

Make Category Model & Migration

<?php


Schema::create('categories', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->text('description')->nullable();
    $table->timestamps();
});

Make controller CategoryController

<?php

class CategoryController extends Controller
{
    public function index()
    {
        return Inertia::render('Categories/Index', [
            'categories' => Category::all(),
        ]);
    }
    public function create()
    {
        return Inertia::render('Categories/Create');
    }
    public function store(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'description' => 'nullable|string',
        ]);
        Category::create($request->all());
        return redirect()->route('categories.index')->with('success', 'Category created successfully.');
    }
    public function edit(Category $category)
    {
        return Inertia::render('Categories/Edit', [
            'category' => $category,
        ]);
    }
    public function update(Request $request, Category $category)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'description' => 'nullable|string',
        ]);
        $category->update($request->all());
        return redirect()->route('categories.index')->with('success', 'Category updated successfully.');
    }
    public function destroy(Category $category)
    {
        $category->delete();
        return redirect()->route('categories.index')->with('success', 'Category deleted successfully.');
    }
}

Create Three Files, resources/js/Pages/Category/Index.vue, resources/js/Pages/Category/Create.vue & resources/js/Pages/Category/Edit.vue

<!-- Index.vue -->
<template>


  <Head title="Categories" /><AuthenticatedLayout><template #header><div class="flex items-center justify-between"><h2 class="text-xl font-semibold leading-tight text-gray-800 dark:text-gray-200">
          Categories
        </h2><PrimaryButton><Link href="/categories/create" class="btn btn-primary">+ Create Category</Link></PrimaryButton></div></template><div class="py-12"><div class="mx-auto max-w-7xl sm:px-6 lg:px-8"><div class="overflow-hidden bg-white shadow-sm sm:rounded-lg dark:bg-gray-800"><div class="p-6 text-gray-900 dark:text-gray-100"><div><!-- <div v-if="$page.props.flash.success" class="alert alert-success">
                {{ $page.props.flash.success }}
              </div> --><Alert v-if="$page.props.flash.success" type="success" :message="$page.props.flash.success" />


              <table class="table-auto w-full border border-gray-200 dark:border-gray-700"><thead class="bg-gray-100 dark:bg-gray-700"><tr><th class="px-4 py-2 text-left text-gray-600 dark:text-gray-300">ID</th><th class="px-4 py-2 text-left text-gray-600 dark:text-gray-300">Name</th><th class="px-4 py-2 text-left text-gray-600 dark:text-gray-300">Description</th><th class="px-4 py-2 text-left text-gray-600 dark:text-gray-300">Actions</th></tr></thead><tbody><tr v-for="category in categories" :key="category.id" class="border-t border-gray-200 dark:border-gray-700"><td class="px-4 py-2">{{ category.id }}</td><td class="px-4 py-2">{{ category.name }}</td><td class="px-4 py-2">{{ category.description }}</td><td><button class="text-indigo-600 hover:underline"><Link :href="`/categories/${category.id}/edit`" class="btn btn-sm btn-warning me-2">Edit</Link></button>
                      
                      <button @click="deleteCategory(category.id)" class="btn btn-sm btn-danger">Delete</button></td></tr></tbody></table></div></div></div></div></div>


  </AuthenticatedLayout>
</template>


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




defineProps({
  categories: Array,
});


const deleteCategory = (id) => {
  if (confirm('Are you sure you want to delete this category?')) {
    router.delete(`/categories/${id}`);
  }
};
</script>



<!-- Create.vue -->
<template>


    <Head title="Create Category" /><AuthenticatedLayout><template #header><h2class="text-xl font-semibold leading-tight text-gray-800 dark:text-gray-200"
            >
                Create Category
            </h2></template>


        <div class="py-12"><div class="mx-auto max-w-7xl sm:px-6 lg:px-8"><div class="overflow-hidden bg-white shadow-sm sm:rounded-lg dark:bg-gray-800"><div class="p-6 text-gray-900 dark:text-gray-100"><div><form @submit.prevent="submit"><div class="mb-3"><InputLabel value="Name" /><TextInput v-model="form.name" id="name" class="mt-1 block w-full" /><InputError class="mt-2" :message="form.errors.name" /><!-- <div v-if="form.errors.name" class="text-danger">{{ form.errors.name }}</div> --></div><div class="mb-3"><label for="description" class="form-label">Description</label><!-- <textarea v-model="form.description" class="form-control" id="description"></textarea> --><TextInput v-model="form.description" id="description" class="mt-1 block w-full" /><!-- <TextInput v-model="form.description" descriptionid="name" /> --></div><SecondaryButton type="submit" value="Save":disabled="form.processing" >
                                    Save
                                </SecondaryButton>
                                
                                <Link href="/categories" class="btn btn-secondary ms-2">Cancel</Link></form></div></div></div></div></div>


    </AuthenticatedLayout>
</template>


<script setup>
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
import TextInput from '@/Components/TextInput.vue';
import InputLabel from '@/Components/InputLabel.vue';
import InputError from '@/Components/InputError.vue';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import { Link, router } from '@inertiajs/vue3';
import { Head } from '@inertiajs/vue3';
import { useForm } from '@inertiajs/vue3';


const form = useForm({
    name: '',
    description: '',
});


const submit = () => {
    form.post('/categories');
};
</script>



<!-- Edit.vue -->
<template>


    <Head title="Update Category" /><AuthenticatedLayout><template #header><h2 class="text-xl font-semibold leading-tight text-gray-800 dark:text-gray-200">
                Update Category
            </h2></template>


        <div class="py-12"><div class="mx-auto max-w-7xl sm:px-6 lg:px-8"><div class="overflow-hidden bg-white shadow-sm sm:rounded-lg dark:bg-gray-800"><div class="p-6 text-gray-900 dark:text-gray-100"><form @submit.prevent="submit"><div class="mb-3"><InputLabel value="Name" /><TextInput v-model="form.name" id="name" class="mt-1 block w-full" /><InputError class="mt-2" :message="form.errors.name" /><!-- <label for="name" class="form-label">Name</label>
                                <input type="text" class="form-control" id="name" required>
                                <div v-if="form.errors.name" class="text-danger">{{ form.errors.name }}</div> --></div><!-- <div class="mb-3">
                                <label for="description" class="form-label">Description</label>
                                <textarea v-model="form.description" class="form-control" id="description"></textarea>
                            </div> --><div class="mb-3"><label for="description" class="form-label">Description</label><!-- <textarea v-model="form.description" class="form-control" id="description"></textarea> --><TextInput v-model="form.description" id="description" class="mt-1 block w-full" /><!-- <TextInput v-model="form.description" descriptionid="name" /> --></div><SecondaryButton type="submit" value="Save" :disabled="form.processing">
                                Save
                            </SecondaryButton>


                            <Link href="/categories" class="btn btn-secondary ms-2">Cancel</Link></form></div></div></div></div>


    </AuthenticatedLayout>
</template>


<script setup>
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout.vue';
import TextInput from '@/Components/TextInput.vue';
import InputLabel from '@/Components/InputLabel.vue';
import InputError from '@/Components/InputError.vue';
import SecondaryButton from '@/Components/SecondaryButton.vue';
import { Link, router } from '@inertiajs/vue3';
import { Head } from '@inertiajs/vue3';
import { useForm } from '@inertiajs/vue3';


const props = defineProps({
    category: Object,
});


const form = useForm({
    name: props.category.name,
    description: props.category.description,
});


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

added following lines in web.php

Route::resource('categories', CategoryController::class);


To Get Demo Visit https://github.com/vivek-mistry/ExploreLaravelVue.git

Share: