Tập tành Phân trang kết quả với Laravel Pagination

14th Jan 2023
Tập tành Phân trang kết quả với Laravel Pagination
Table of contents

Trong bài Xây dựng truy vấn bằng Laravel Query Builder chúng ta có một ví dụ trong đó tạo một trang chứa danh sách các sản phẩm. Danh sách này có 4 sản phẩm nên chưa cần phân trang, nếu số lượng sản phẩm lên đến vài chục sản phẩm, chúng ta cần phân trang, mỗi trang sẽ chỉ chứa 5 sản phẩm giúp cho quản lý tốt hơn. Laravel Pagination giúp cho việc phân trang ngay khi xây dựng các truy vấn một cách rất dễ dàng, ngoài ra tính năng phân trang này còn tự sinh mã HTML phù hợp với cách thiết kế trang web sử dụng Bootstrap.

Phân trang kết quả truy vấn trong Laravel

Laravel sử dụng phương thức paginate() để phân trang, xem ví dụ sau để hiểu hơn cách sử dụng:

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $products = DB::table('products')->paginate(5);
        return view('fontend.product.list')->with($products);
    }

phương thức paginate() có thể sử dụng cho cả Query Builder và Eloquent ORM, nó tự động tính toán số lượng trang, các bản ghi nào thuộc trang... Trang hiện tại sẽ được phát hiện trong qua tham số page trong query string của URL. Hiển thị kết quả phân trang trong view chỉ đơn giản như sau (sửa luôn view list.blade.php trong resources/views/fontend/product):

@extends('layouts.default')

@section('title', 'Danh sách sản phẩm')

@section('content')
    <table class="table table-bordered">
        <tr class="success">
            <th>ID</th>
            <th>Tên sản phẩm</th>
            <th>Giá sản phẩm</th>
            <th>Nội dung</th>
            <th>Ảnh sản phẩm</th>
            <th>Đăng bán</th>
            <th>Action</th>
        </tr>
        @foreach($products as $p)
        <tr>
            <td>{{ $p->id }}</td>
            <td>{{ $p->name }}</td>
            <td class="text-right">{{ number_format($p->price) }}</td>
            <td>{{ $p->content }}</td>
            <td>
                <img src="{{ Asset($p->image_path) }}" alt="{{ $p->name }}" width="120" height="120">
            </td>
            <td>
                @if($p->active)
                    <span class="text-success glyphicon glyphicon-ok"></span>
                @else
                    <span class="text-danger glyphicon glyphicon-remove"></span>
                @endif
            </td>
            <td>
                <a href="{{ '/product/' . $p->id . '/edit'}}"><span class="glyphicon glyphicon-pencil">Edit</span></a>
                <a href="{{ '/product/' . $p->id }}"><span class="glyphicon glyphicon-trash">Delete</span></a>
            </td>
        </tr>
        @endforeach
    </table>
    {{ $products->links() }}
@endsection

Chúng ta thấy việc chèn vào kết quả phân trang chỉ đơn giản là thêm

    {{ $products->links() }}

Chúng ta nhập thêm một số sản phẩm nữa cho danh sách hơn 5 sản phẩm và vào lại trang danh sách sản phẩm http://laravel.dev/product xem phân trang thế nào. Các URL trong phân trang sẽ có dạng http://laravel.dev/product?page=x, x là trang hiện hành. Nếu bạn muốn thêm các tham số query string vào URL này, sử dụng phương thức appends(), ví dụ bạn muốn phân trang các sản phẩm có giá từ 300k đến 600k chẳng hạn, đường dẫn sẽ có dạng http://laravel.dev/product?page=x&minprice=300000&maxprice=600000.

    {{ $products->appends(['minprice' => 300000, 'maxprice' => 600000])->links() }}

Chỉnh sửa giao diện phân trang

Như đã nói ở phần đầu, mặc định giao diện phần phân trang trong Laravel Pagination tạo ra mã HTML tương thích với Bootstrap, chính vì vậy nếu bạn không sử dụng Bootstrap làm CSS framework chính của project bạn có thể chỉnh sửa giao diện phần phân trang như sau:

    {{ $products->links('pagination') }}

với pagination.blade.php là một view nằm trong resources/views, chúng ta cũng hoàn toàn có thể truyền tham số cho view này bằng cách:

    {{ $products->links('view.pagination', ['minprice' => 300000, 'maxprice' => 600000]) }}

Một cách khác để chỉnh sửa giao diện phần phân trang là chỉnh sửa ngay trên chính view mặc định của Laravel bằng cách export chúng vào thư mục resouces/views/vendor sử dụng câu lệnh

php artisan vendor:publish --tag=laravel-pagination

Câu lệnh này sẽ export ra một view default.blade.php nằm trong resouces/views/vendor/pagination và bạn chỉ đơn giản là chỉnh sửa các mã HTML và CSS trong view này.

Các phương thức khác sử dụng trong Laravel Pagination

Laravel còn cung cấp một số phương thức khác liên quan đến phân trang, các phương thức này có thể sử dụng khi bạn muốn xây dựng giao diện phần phân trang riêng.

$products = DB::table('products')->where('active', '=', 1)->paginate(5);

// Số trang trong kết quả $products trả về

$products->count()

// Trang hiện tại trong phần phân trang
$results->currentPage()

$results->firstItem()
$results->hasMorePages()
$results->lastItem()

// Trang cuối cùng trong phân trang
$results->lastPage()

// Trang tiếp theo trong phân trang
$results->nextPageUrl()
$results->perPage()

// Trang trước đó trong phân trang
$results->previousPageUrl()

$results->total()
$results->url($page)

Lấy một trường hợp đơn giản đặt ra:

Mình sẽ làm một ví dụ đơn giản như thế này: Lấy hết các sản phẩm trong bảng products rồi phân trang cho nó. Bạn nào làm Laravel rồi sẽ biết trong framework này có phương thức ->paginate() để phân trang, sau đó qua bên view để hiển thị dữ liệu. 

Để kết hợp Ajax vào phân trang chúng ta sẽ làm thêm một bước nữa là viết code javascript ở bên trang view mà ta cho hiển thị cái phân trang đó.

1 – Viết Route và Controller

Vì route và controller cho ví dụ này khá ngắn nên mình gộp chung lại trong mục 1 này nhé.

Bạn vào  routes/web.php trong project laravel của bạn và thêm dòng code này vào:

<?php
Route::get('/', 'FrontEndController@get_home');

Tiếp theo bạn mở cmd đến thư mục project Laravel của bạn và chạy câu lệnh để tạo Controller:

php artisan make:controller FrontEndController

Sau đó vào app/Http/Controllers sẽ thấy file FrontEndController.php chúng ta sẽ viết function get_home trong file này:

Nội dung file FrontEndController.php:

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Product;
class FrontEndController extends Controller
{
    public function get_home(Request $request){
        if($request->ajax() || 'NULL'){
          $products = Product::all();
          return view('front.pages.home',compact('products'));
        }
    }
}

Ở đoạn code trên mình lấy ra toàn bộ danh sách sản phẩm bằng Product::all() đây là cách viết Query Builder và Model trong Laravel, nếu đã đọc tới bài phân trang này thì mình chắc các bạn đã nắm được rồi. Còn bạn nào chưa nắm được thì xem tại docs của Laravel nhé.

Hoặc các bạn cũng có thể viết:

$products = DB::table('products')->get();
//hoặc
$products = DB::raw('select * from products');
//tùy cách các bạn muốn dùng thôi

2 – Viết View và code Ajax

Sau khi viết Controller ở trên, mình truyền dữ liệu products về view home.blade.php

Các bạn tạo thư mục bên trong resources/views theo cấu trúc sau: front/pages/home.blade.php

Code trong file home này như sau:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Demo Paginate - Trung Quân</title>
    <base href="{{ asset('') }}">
    <link href='http://fonts.googleapis.com/css?family=Dosis:300,400' rel='stylesheet' type='text/css'>
    <link href='http://fonts.googleapis.com/css?family=Open+Sans:400,300' rel='stylesheet' type='text/css'>
    <script src="http://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
    <script src="http://code.jquery.com/jquery-3.2.1.js" integrity="sha256-DZAnKJ/6XZ9si04Hgrsxu/8s717jcIzLy3oi35EouyE=" crossorigin="anonymous"></script>
  </head>
  <body>
    <div class="show-products">
      @foreach($products as $product)
      {{ $product->name }} <br>
      @endforeach
    </div>
    {!! $products->links() !!}
    <script>
      $('.pagination a').unbind('click').on('click', function(e) {
             e.preventDefault();
             var page = $(this).attr('href').split('page=')[1];
             getPosts(page);
       });
      
       function getPosts(page)
       {
            $.ajax({
                 type: "GET",
                 url: '?page='+ page
            })
            .success(function(data) {
                 $('body').html(data);
            });
       }
    </script>
  </body>
</html>
Bạn thấy bài viết này như thế nào?
2 reactions

Add new comment

Image CAPTCHA
Enter the characters shown in the image.

Related Articles

Hiện nay kiến trúc Microservices đang là chủ đề được cộng đồng Developer vô cùng quan tâm

Hôm nay chúng ta cùng tìm hiểu về Eloquent trong Laravel với mối quan hệ nhiều - nhiều (many to many relationship)

Kiểm soát hợp lí truy cập nội dung trang web là yếu tố quyết định trong việc điều hành một máy chủ bảo mật.

Trong lập trình web, authorization (phân quyền) là chức năng vô cùng quan trọng và không thể thiếu

Trước đây, với các dự án được quản lý source code trên Github, chúng ta thường cần sử dụng thêm một số CI/CD service như Jenkins