Build Mini App CRUD With Laravel And Vuejs
Lượt xem: 6509
CRUD (Create, Read, Update, and Delete) là các thao tác dữ liệu cơ bản và là một trong những điều đầu tiên bạn học với tư cách là nhà phát triển Laravel.
Trong ví dụ này Laravel Vuejs CRUD, Chúng ta sẽ tìm hiểu cách triển khai Laravel Vuejs CRUD (create, read, update, and delete) spa (Single Page Application) với Vue.js , Vue Router và Laravel Framework.
Ngày nay, các framework JS phổ biến nhất là Angular JS và Vue JS. Angular JS và Vue JS là những framework JS rất thân thiện với người dùng và phổ biến nhất. Nó cung cấp khả năng quản lý toàn bộ dự án hoặc ứng dụng mà không cần làm mới trang và xác thực jquery mạnh mẽ.
1. Cài đặt dự án Laravel (Install Laravel Project)
Đầu tiên, mở Terminal và chạy lệnh sau để tạo một dự án laravel mới:
composer create-project --prefer-dist laravel/laravel crud-spa
hoặc, nếu bạn đã cài đặt Trình cài đặt Laravel
laravel new crud-spa
2. Định cấu hình chi tiết cơ sở dữ liệu
Sau khi cài đặt Đi tới thư mục gốc của dự án, mở tệp .env và đặt chi tiết cơ sở dữ liệu như sau:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=[DATABASE NAME] //larave_vuejs
DB_USERNAME=[DATABASE USERNAME] //root
DB_PASSWORD=[DATABASE PASSWORD] //
3.Cài đặt phụ thuộc NPM
Chạy lệnh sau để cài đặt các phần phụ thuộc của giao diện người dùng:
npm install
Lưu ý: Máy cần phải cài đặt Nodejs trước đó. Xem thêm cài đặt Nodejs trên windows 10
Tiếp theo, cài đặt vue , vue-router và vue-axios . Vue-axios sẽ được sử dụng để gọi API của Laravel. Chạy lệnh sau trên terminal:
npm install vue vue-router vue-axios --save
Xem thêm làm quen nhanh với laravel
4.Tạo di chuyển (migrate), mô hình (model) và bộ điều khiển (controller)
Tạo Category model (mô hình) migrate (di chuyển) và controller (bộ điều khiển). Chạy lệnh sau cho điều đó:
php artisan make:model Category -mcr
-mcr đối số này sẽ tạo model, migrate và controller trong một lệnh đơn.
Bây giờ, hãy mở tệp migrate của cateogry (danh mục) từ folder database/migrations và thay thế mã trong hàm up ():
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('title');
$table->text('description');
$table->timestamps();
});
}
Migrate database chúng ta sử dụng lệnh:
php artisan migrate
Bây giờ, hãy mở model Category.php từ App/Models và cập nhật mã vào model Category.php:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Category extends Model {
use HasFactory;
protected $fillable = ['title','description'];
}
?>
Tiếp theo, mở CategoryController.php và thêm mã vào các phương thức index, store, update và delete như sau:
<?php
namespace App\Http\Controllers;
use App\Models\Category;
use Illuminate\Http\Request;
class CategoryController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$categories = Category::all(['id','title','description']);
return response()->json($categories);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$category = Category::create($request->post());
return response()->json([
'message'=>'Category Created Successfully!!',
'category'=>$category
]);
}
/**
* Display the specified resource.
*
* @param \App\Models\Category $category
* @return \Illuminate\Http\Response
*/
public function show(Category $category)
{
return response()->json($category);
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Category $category
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Category $category)
{
$category->fill($request->post())->save();
return response()->json([
'message'=>'Category Updated Successfully!!',
'category'=>$category
]);
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Category $category
* @return \Illuminate\Http\Response
*/
public function destroy(Category $category)
{
$category->delete();
return response()->json([
'message'=>'Category Deleted Successfully!!'
]);
}
}
5. Xác định tuyến đường (route) trong web.php
Bây giờ hãy xác định các tuyến trong tệp tuyến web.php và api.php. Chuyển đến thư mục tuyến đường và mở tệp web.php và api.php rồi cập nhật các tuyến đường sau:
routes / api.php
Route::resource('category',App\Http\Controllers\CategoryController::class)->only(['index','store','show','update','destroy']);
routes / web.php
Route::get('/', function () {
return view('app');
});
6.Tạo ứng dụng Vue
Trong bước này, hãy chuyển đến thư mục resource/views, tạo tệp app.blade.php và thêm mã sau vào app.blade.php như sau:
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" value="{{ csrf_token() }}"/>
<title> Laravel Vue CRUD App - dandevblog</title>
<link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet" type="text/css">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
@vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
<div id="app">
</div>
</body>
</html>
7.Tạo thành phần (components) cho ứng dụng Vue
Trong bước này, hãy chuyển đến thư mục resource/ js, tạo thư mục components và tạo các tệp như sau:
- App.vue
- Welcome.vue
- category / List.vue
- category / Add.vue
- category / Edit.vue
<template>
<div class="container mt-5">>
<div class="col-12 text-center">
<h1>dandevblog</h1>
<a href="https://dandev.net" target="_blank">Visit For More Blogs</a>
</div>
</div>
</template>
Mở tệp App.vue và Cập nhật đoạn mã sau:
<template>
<main>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<router-link to="/" class="navbar-brand" href="#">Laravel Vue Crud App - dandevblog</router-link>
<div class="collapse navbar-collapse">
<div class="navbar-nav">
<router-link exact-active-class="active" to="/" class="nav-item nav-link">Home</router-link>
<router-link exact-active-class="active" to="/category" class="nav-item nav-link">Category</router-link>
</div>
</div>
</div>
</nav>
<div class="container mt-5">
<router-view></router-view>
</div>
</main>
</template>
<script>
export default {}
</script>
Tiếp theo, mở file List.vue trong thư mục components/category/List.vue và thêm mã sau:
<template>
<div class="row">
<div class="col-12 mb-2 text-end">
<router-link :to='{name:"categoryAdd"}' class="btn btn-primary"> Create</router-link>
</div>
<div class="col-12">
<div class="card">
<div class="card-header">
<h4> Category</h4>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th> ID</th>
<th> Title</th>
<th> Description</th>
<th> Actions</th>
</tr>
</thead>
<tbody v-if="categories.length > 0">
<tr v-for="(category,key) in categories" :key="key">
<td> {{ category.id }}</td>
<td> {{ category.title }}</td>
<td> {{ category.description }}</td>
<td>
<router-link :to='{name:"categoryEdit",params:{id:category.id}}' class="btn btn-success"> Edit</router-link>
<button type="button" @click="deleteCategory(category.id)" class="btn btn-danger"> Delete</button>
</td>
</tr>
</tbody>
<tbody v-else>
<tr>
<td colspan="4" align="center"> No Categories Found.</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name:"categories",
data(){
return {
categories:[]
}
},
mounted(){
this.getCategories()
},
methods:{
async getCategories(){
await this.axios.get('/api/category').then(response=>{
this.categories = response.data
}).catch(error=>{
console.log(error)
this.categories = []
})
},
deleteCategory(id){
if(confirm("Are you sure to delete this category ?")){
this.axios.delete(`/api/category/${id}`).then(response=>{
this.getCategories()
}).catch(error=>{
console.log(error)
})
}
}
}
}
</script>
Tiếp theo, mở resources /js / components/ category / Add.vue và cập nhật mã sau:
<template>
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h4> Add Category</h4>
</div>
<div class="card-body">
<form @submit.prevent="create">
<div class="row">
<div class="col-12 mb-2">
<div class="form-group">
<label> Title</label>
<input type="text" class="form-control" v-model="category.title">
</div>
</div>
<div class="col-12 mb-2">
<div class="form-group">
<label> Description</label>
<input type="text" class="form-control" v-model="category.description">
</div>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary"> Save</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name:"add-category",
data(){
return {
category:{
title:"",
description:""
}
}
},
methods:{
async create(){
debugger
await this.axios.post('/api/category',this.category).then(response=>{
this.$router.push({name:"categoryList"})
}).catch(error=>{
console.log(error)
})
}
}
}
</script>
Tiếp theo, mở resources/js/components/category/Edit.vue và cập nhật mã sau:
<template>
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h4>Update Category</h4>
</div>
<div class="card-body">
<form @submit.prevent="update">
<div class="row">
<div class="col-12 mb-2">
<div class="form-group">
<label>Title</label>
<input type="text" class="form-control" v-model="category.title">
</div>
</div>
<div class="col-12 mb-2">
<div class="form-group">
<label>Description</label>
<input type="text" class="form-control" v-model="category.description">
</div>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary">Update</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name:"update-category",
data(){
return {
category:{
title:"",
description:"",
_method:"patch"
}
}
},
mounted(){
this.showCategory()
},
methods:{
async showCategory(){
await this.axios.get(`/api/category/${this.$route.params.id}`).then(response=>{
const { title, description } = response.data
this.category.title = title
this.category.description = description
}).catch(error=>{
console.log(error)
})
},
async update(){
await this.axios.post(`/api/category/${this.$route.params.id}`,this.category).then(response=>{
this.$router.push({name:"categoryList"})
}).catch(error=>{
console.log(error)
})
}
}
}
</script>
8.Xác định tuyến đường (routes) cho ứng dụng Crud trong bộ định tuyến Vue
Bây giờ, bạn cần xác định router Vue, vì vậy hãy chuyển đến thư mục resources/js, tạo tệp routes.js và cập nhật mã sau:
import Welcome from './components/Welcome.vue'
import CategoryList from './components/category/List.vue'
import CategoryCreate from './components/category/Add.vue'
import CategoryEdit from './components/category/Edit.vue'
export const routes = [
{
name: 'home',
path: '/',
component: Welcome
},
{
name: 'categoryList',
path: '/category',
component: CategoryList
},
{
name: 'categoryEdit',
path: '/category/:id/edit',
component: CategoryEdit
},
{
name: 'categoryAdd',
path: '/category/add',
component: CategoryCreate
}
]
9.Thêm các phụ thuộc Vue.js vào app.js
Bây giờ, bạn cần thêm tất cả các routes, vue-axios và các phần phụ thuộc khác.
resources/ js / app.js
import './bootstrap';
import { createApp } from 'vue'
import App from './components/App.vue';
import * as VueRouter from 'vue-router';
import VueAxios from 'vue-axios';
import axios from 'axios';
import {routes} from './routes';
const router = VueRouter.createRouter({
history: VueRouter.createWebHashHistory(),
routes,
})
const app = createApp(App)
.use(router)
.use(VueAxios, axios)
.mount('#app')
10.Cập nhật vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
refresh: true,
}),
vue({
template: {
transformAssetUrls: {
// The Vue plugin will re-write asset URLs, when referenced
// in Single File Components, to point to the Laravel web
// server. Setting this to `null` allows the Laravel plugin
// to instead re-write asset URLs to point to the Vite
// server instead.
base: null,
// The Vue plugin will parse absolute URLs and treat them
// as absolute paths to files on disk. Setting this to
// `false` will leave absolute URLs un-touched so they can
// reference assets in the public directory as expected.
includeAbsolute: false,
},
},
}),
],
});
Thêm vitejs/plugin-vue
npm install --save-dev @vitejs/plugin-vue
11. Chạy máy chủ phát triển
npm run dev
Lưu ý: ở đây mình dùng xampp làm server chạy laravel chứ không dùng php artisan (bạn có thể dùng php artisan để chạy laravel). Xem them cấu hình domain bất kỳ chạy trong mạng lan với xampp
Video thao tác cùng dandev