post-image

Xây dựng ứng dụng CRUD sử dụng Vue.js trong Laravel

Tổng quan

CRUD viết tắt của Create, Read, Update, Delete là một thuật ngữ lập trình nói đến 4 phương thức quen thuộc khi làm việc với kho dữ liệu. Ứng dụng CRUD là ứng dụng cung cấp đủ các hoạt động trên cùng với phân trang và tìm kiếm. Ứng dụng CRUD là rất thuận tiện trong việc sử dụng đem lại trải nghiệm tốt cho người dùng.

Trong bài viết này, chúng ta sẽ tìm hiểu cách xây dựng một ứng dụng CRUD để quản lý các sản phẩm, ứng dụng sẽ sử dụng framework Vue.js một framework javascript được Laravel khuyến cáo sử dụng. Trong bài viết Xây dựng truy vấn cùng Laravel query builder, chúng ta cũng đã xây dựng một ứng dụng CRUD cho việc quản lý sản phẩm. Tuy nhiên, bài viết này hướng đến việc sử dụng Vue.js, bạn sẽ thấy những trải nghiệm khác biệt.

Ứng dụng CRUD sử dụng Vue.js trong Laravel

Bước 1: Xây dựng database

Trong các viết trước chúng ta đã xây dựng project laravel-test để thực hành cho các bài viết (xem khóa học Laravel 7 ngày để biết thêm chi tiết). Nếu bạn sử dụng laravel-test thì đã có sẵn bảng product nên ta có thể bỏ qua bước này. Sử dụng Laravel Migration để tạo bảng.

c:\xampp\htdocs\laravel-test>php artisan make:migration create_products_table --create=products Created Migration: 2017_04_24_024728_create_products_table

Thêm code tạo bảng product vào file 2017_04_24_024728_create_products_table

<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateProductsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('products', function (Blueprint $table) { $table->increments('id'); $table->string('name', 255); $table->integer('price'); $table->text('content'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('products'); } }
Code language: HTML, XML (xml)

Chạy lệnh php artisan migrate để tạo ra bảng product trong CSDL.

c:\xampp\htdocs\laravel-test>php artisan migrate Migrated: 2017_04_24_024728_create_products_table

Bước 2: Tạo VueJSProductController xử lý các hoạt động trên sản phẩm

Chúng ta sẽ tạo ra một RESTful Controller có sẵn các phương thức cho từng hoạt động trên sản phẩm (Xem Laravel Controller để hiểu hơn về RESTful Controller). Cũng vẫn sử dụng câu lệnh artisan make:controller nhưng thêm tham số –resource để tạo RESTful Controller:

php artisan make:controller VueJSProductController --resource
Code language: CSS (css)

Tôi sử dụng tên VueJSProductController để tránh bị trùng với ProductController đã có sẵn trong laravel-test. Tiếp theo, đưa code vào VueJSProductController:

<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Product; class VueJSProductController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index(Request $request) { $products = Product::latest()->paginate(5); $response = [ 'pagination' => [ 'total' => $products->total(), 'per_page' => $products->perPage(), 'current_page' => $products->currentPage(), 'last_page' => $products->lastPage(), 'from' => $products->firstItem(), 'to' => $products->lastItem() ], 'data' => $products ]; return response()->json($response); } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { // } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $this->validate($request, [ 'name' => 'required', 'price' => 'required', 'content' => 'required', ]); $create = Product::create($request->all()); return response()->json($create); } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { // } /** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { // } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { $this->validate($request, [ 'name' => 'required', 'price' => 'required', 'content' => 'required', ]); $edit = Product::find($id)->update($request->all()); return response()->json($edit); } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy($id) { Product::find($id)->delete(); return response()->json(['done']); } public function showVueProduct(){ return view('fontend.vue-product'); } }
Code language: HTML, XML (xml)

Bước 3: Tạo route và view

Tạo view vue-product.blade.php trong resources/views/fontend, chú ý chèn vào các thư viện vue.js và toastr (sử dụng để hiển thị thông báo trên trình duyệt).

@extends('layouts.default') @section('title', 'Referral system - Allaravel.com') @section('link-header') <link href="//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/css/toastr.min.css" rel="stylesheet"> <meta id="token" name="token" value="{{ csrf_token() }}"> @endsection @section('content') <div class="container" id="manage-vue"> <div class="row"> <div class="col-lg-12 margin-tb"> <div class="pull-left"> <h2>Laravel + VueJS Product CRUD</h2> </div> <div class="pull-right"> <button type="button" class="btn btn-success" data-toggle="modal" data-target="#create-item"> Tạo sản phẩm mới </button> </div> </div> </div> <!-- Item Listing --> <div class="row"> <div class="col-md-12"> <table class="table table-bordered"> <tr> <th class="col-md-2">Name</th> <th class="col-md-1">Price</th> <th class="col-md-7">Content</th> <th class="col-md-2">Action</th> </tr> <tr v-for="item in items"> <td>@{{ item.name }}</td> <td>@{{ item.price }}</td> <td>@{{ item.content }}</td> <td> <button class="btn btn-primary" @click.prevent="editItem(item)">Edit</button> <button class="btn btn-danger" @click.prevent="deleteItem(item)">Delete</button> </td> </tr> </table> <!-- Pagination --> <nav> <ul class="pagination"> <li v-if="pagination.current_page > 1"> <a href="#" aria-label="Previous" @click.prevent="changePage(pagination.current_page - 1)"> <span aria-hidden="true">«</span> </a> </li> <li v-for="page in pagesNumber" v-bind:class="[ page == isActived ? 'active' : '']"> <a href="#" @click.prevent="changePage(page)">@{{ page }}</a> </li> <li v-if="pagination.current_page < pagination.last_page"> <a href="#" aria-label="Next" @click.prevent="changePage(pagination.current_page + 1)"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav> </div> </div> <!-- Create Item Modal --> <div class="modal fade" id="create-item" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">Tạo sản phẩm mới</h4> </div> <div class="modal-body"> <form method="POST" enctype="multipart/form-data" v-on:submit.prevent="createItem"> <div class="form-group"> <label for="name">Name:</label> <input type="text" name="name" class="form-control" v-model="newItem.name" /> <span v-if="formErrors['name']" class="error text-danger">@{{ formErrors['name'] }}</span> </div> <div class="form-group"> <label for="price">Price:</label> <input type="text" name="price" class="form-control" v-model="newItem.price" /> <span v-if="formErrors['price']" class="error text-danger">@{{ formErrors['price'] }}</span> </div> <div class="form-group"> <label for="content">Content:</label> <textarea name="content" class="form-control" v-model="newItem.content"></textarea> <span v-if="formErrors['content']" class="error text-danger">@{{ formErrors['content'] }}</span> </div> <div class="form-group"> <button type="submit" class="btn btn-success">Tạo sản phẩm</button> </div> </form> </div> </div> </div> </div> <!-- Edit Item Modal --> <div class="modal fade" id="edit-item" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">Chỉnh sửa sản phẩm</h4> </div> <div class="modal-body"> <form method="POST" enctype="multipart/form-data" v-on:submit.prevent="updateItem(fillItem.id)"> <div class="form-group"> <label for="name">Name:</label> <input type="text" name="name" class="form-control" v-model="fillItem.name" /> <span v-if="formErrorsUpdate['name']" class="error text-danger">@{{ formErrorsUpdate['name'] }}</span> </div> <div class="form-group"> <label for="price">Price:</label> <input type="text" name="price" class="form-control" v-model="fillItem.price" /> <span v-if="formErrorsUpdate['price']" class="error text-danger">@{{ formErrorsUpdate['price'] }}</span> </div> <div class="form-group"> <label for="content">Content:</label> <textarea name="content" class="form-control" v-model="fillItem.content"></textarea> <span v-if="formErrorsUpdate['content']" class="error text-danger">@{{ formErrorsUpdate['content'] }}</span> </div> <div class="form-group"> <button type="submit" class="btn btn-success">Cập nhật sản phẩm</button> </div> </form> </div> </div> </div> </div> </div> @endsection @section('js') <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/js/toastr.min.js"></script> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.26/vue.min.js"></script> <script type="text/javascript" src="https://cdn.jsdelivr.net/vue.resource/0.9.3/vue-resource.min.js"></script> <script type="text/javascript" src="{{ Asset('js/product.js') }}"></script> @endsection
Code language: JavaScript (javascript)

Tạo route trong routes/web.php

Route::get('/vue-product', 'VueJSProductController@showVueProduct'); Route::resource('vueproduct','VueJSProductController');
Code language: PHP (php)

Bước 4: Tạo file product.js chứa code Vue.js

Tham khảo các bài viết về Vue.js Framework trước khi thực hiện code product.js, những hướng dẫn cơ bản giúp bạn hiểu nhanh chóng ví dụ CRUD.

Vue.http.headers.common['X-CSRF-TOKEN'] = $("#token").attr("value"); new Vue({ el: '#manage-vue', data: { items: [], pagination: { total: 0, per_page: 2, from: 1, to: 0, current_page: 1 }, offset: 4, formErrors:{}, formErrorsUpdate:{}, newItem : {'name':'','price':'','content':''}, fillItem : {'name':'','price':'','content':'','id':''} }, computed: { isActived: function () { return this.pagination.current_page; }, pagesNumber: function () { if (!this.pagination.to) { return []; } var from = this.pagination.current_page - this.offset; if (from < 1) { from = 1; } var to = from + (this.offset * 2); if (to >= this.pagination.last_page) { to = this.pagination.last_page; } var pagesArray = []; while (from <= to) { pagesArray.push(from); from++; } return pagesArray; } }, ready : function(){ this.getvueproduct(this.pagination.current_page); }, methods : { getvueproduct: function(page){ this.$http.get('/vueproduct?page='+page).then((response) => { this.$set('items', response.data.data.data); this.$set('pagination', response.data.pagination); }); }, createItem: function(){ var input = this.newItem; this.$http.post('/vueproduct',input).then((response) => { this.changePage(this.pagination.current_page); this.newItem = {'name':'','price':'','content':''}; $("#create-item").modal('hide'); toastr.success('Item Created Successfully.', 'Success Alert', {timeOut: 5000}); }, (response) => { this.formErrors = response.data; }); }, deleteItem: function(item){ this.$http.delete('/vueproduct/'+item.id).then((response) => { this.changePage(this.pagination.current_page); toastr.success('Item Deleted Successfully.', 'Success Alert', {timeOut: 5000}); }); }, editItem: function(item){ this.fillItem.name = item.name; this.fillItem.id = item.id; this.fillItem.price = item.price; this.fillItem.content = item.content; $("#edit-item").modal('show'); }, updateItem: function(id){ var input = this.fillItem; this.$http.put('/vueproduct/'+id,input).then((response) => { this.changePage(this.pagination.current_page); this.fillItem = {'name':'','price':'','content':'','id':''}; $("#edit-item").modal('hide'); toastr.success('Item Updated Successfully.', 'Success Alert', {timeOut: 5000}); }, (response) => { this.formErrorsUpdate = response.data; }); }, changePage: function (page) { this.pagination.current_page = page; this.getvueproduct(page); } } });
Code language: JavaScript (javascript)

Bước 5: Kiểm tra kết quả ứng dụng CRUD quản lý sản phẩm

Vào đường dẫn http://laravel.dev/vue-product chúng ta thấy các sản phẩm được liệt kê từ CSDL đã được phân trang.

Ứng dụng quản lý sản phẩm CRUD sử dụng Vuejs

Khi click vào Tạo sản phẩm mới, một Modal hiện ra

Tạo sản phẩm mới trong ứng dụng Vuejs CRUD

Sử dụng ứng dụng CRUD kết hợp với Vue.js cho thấy một số ưu điểm như sau:

Trải nghiệm người dùng

  • Các thao tác với sản phẩm như create, edit, delete, phân trang… rất thuận tiện và tốc độ xử lý nhanh, không phải tải qua lại nhiều trang.
  • Các thao tác trực quan hơn, giao diện kết hợp Modal rất hiện đại.

Lập trình viên

  • Viết code ngắn gọn hơn, thay vì trước đây phải viết thiết kế nhiều view thì giờ chỉ cần 1 view cho toàn bộ một CRUD của một đối tượng.
  • Tạo ít request hơn đến máy chủ.

Laravel hiện đang là PHP framework số một hiện nay, giờ kết hợp cùng với Vue.js và Bootstrap, OMG không còn gì để nói, bạn có thể xây dựng những ứng dụng web tuyệt vời, cực nhanh, mạnh và hơn hết là mang lại một trải nghiệm tốt cho người dùng.

Cảm ơn các bạn đã đọc.

Các bạn có thể tham khảo các bài viết hay về Laravel tại đây.


Hãy tham gia nhóm Học lập trình để thảo luận thêm về các vấn đề cùng quan tâm.

Nguồn tham khảo: Allaravel

Leave a Reply

Your email address will not be published. Required fields are marked *