Dùng Ajax để phân trang trong Datatable

Datatables là plugin rất phổ biến cho những trang trang admin muốn quản lý dữ liệu. Ở bài hướng dẫn này mình sẽ bỏ qua phần giới thiệu về plugin này. Các bạn có thể vào trang chủ của nó để đọc nhé. Link: https://datatables.net/
Thường thường mình thấy các bạn dùng datatables thường get hết dữ liệu ra 1 lần rồi bỏ vào để nó tự phân trang. Cách làm này mới đầu thì nhìn có vẻ nhanh và tiện. Nhưng theo thời gian, dữ liệu của database nhiều lên. Mỗi lần bạn get all như vậy sẽ khiến trang web của mình rất chậm or có thể ko thể load trang vì dữ liệu quá lớn. Datatables có support lấy dữ liệu bằng ajax rất nhanh và tiện. Các bạn có thể xem ở đây: https://datatables.net/examples/data_sources/server_side.html
Hoặc xem ở bài viết này của mình nhé.
Ở đây mình dùng laravel 5 cùng vs jquery nhé.

Về phần html thì mình sẽ không đưa vào đây vì nếu ai đã sử dụng datatable thì việc này quá dễ dàng rồi. chỉ cần đặt tên class or id rồi gọi từ js là xong.

Mình tạo file example_datatables_with_ajax.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
initDataTable = function(tableId) {
  if (!$.fn.dataTable.isDataTable(tableId)) {
    $(tableId).DataTable({
      // "order": [[0, "desc"]],
      // "lengthMenu": [[10, 25, 50, 100], [10, 25, 50, 100]],
      "pagingType": "full_numbers",
      "processing": true,
        "serverSide": true,
        // "stateSave": true,
        "ajax": ajax_url,
        "columns" : [
          { "data" : 0, orderable: false},
          { "data" : 1, orderable: true},
          { "data" : 2, orderable: false },
          { "data" : 3, orderable: false },
          { "data" : 4, orderable: false },
          { "data" : 5, orderable: false },
          { "data" : 6, orderable: false },
          {
            "data" : 7,
            render: function(data, type, row, meta) {
                return '<a class="btn btn-raised btn-info btn-xs" data-href="" data-toggle="modal" data-transaction-id="' + data + '" data-target="#edit_transaction"><i class="glyphicon glyphicon-pencil" aria-hidden="true"></i></a>'
                        + '<a class="btn btn-raised btn-danger btn-xs" data-href="" data-toggle="modal" data-target="#deleteTransaction"><i class="glyphicon glyphicon-remove" aria-hidden="true"></i></a>';
   
              else return data;
            },
            orderable: false
          },
        ],
        "deferLoading": total,
        "deferRender": true
    });
  }
}
initDataTable("#table-example");

 - Cùng phân tích đoạn code trên nhé:
lengthMenu: nghĩa là bạn sẽ cho table hiện 1 lúc bao nhiêu items. ở trên thì bạn có thể thấy mình để 10,25,50,100. Bạn có thể chỉnh sửa theo ý của bạn or dùng mặc đinh thì ko cần phải dùng biến này.
pagingType: là kiểu phân trang.
processing: là môĩ khi chạy ajax sẽ có icon cho ng dùng biết table đang load dữ liệu.
serverSide: true để có thể dùng ajax
ajax: đường dẫn để get dữ liệu (cái này mình sẽ nói sau)
columns: Ở đây bạn có thể dùng mặc định or chỉnh sửa lại theo ý mình. như đây thì mình có set các trường cho phép sắp xếp và các trường ko đc. Cùng với thay đổi lại template của column (xem ở column thứ 7)  dùng để edit và delete.
deferLoading: bạn dùng 1 function để count toàn bộ dữ liệu (chỉ count chứ ko lấy hết dữ liệu nhé) rồi set vào đây để datatables biết được để phân trang cho đúng.
Sau khi đã setup xong thì chỉ cần gọi tới table cần dùng bằng dòng code này: initDataTable("#table-example");

- Giờ đến phần controller. Giả sử mình có server ExampleController.php. Đây là function index để load trang trong lần đầu:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public function index()
    {
        // Ví dụ ở đây mình set limit = 10. Thì trong setting của datable bạn cũng phải set lengthMenu đầu tiên bằng 10 nhé. Để cho đồng bộ giữa server datatables.
        $items = $this->transactionRepo->getPaginated(Transaction::STATUS_ACTUAL, $this->limit);
     
       // Ở bên laravel có support cách truyền biến qua file js bằng cách này. Cái này dùng để count all items.
       JavaScript::put([
            'total' => $items->total(),
        ]);
        return view('example::a.index', compact('items'));
    }

- Tiếp theo là phần quan trọng nhất. Đây chính là function dùng để get dữ liệu bằng phân trang.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
 public function getItemsData()
    {
        // print_r(request()->all()); Các bạn có thể dump ra request để dễ dàng thấy những param được truyền vào từ datatable nhé.
        if (request()->ajax()) {
           //Ở đây các biến khá trực quan rồi nên mình ko giải thích thêm nữa. Cái này là mình lấy các biến cho đúng dựa theo cấu trúc của datatable đưa.  Nên các bạn đừng hỏi là vì sao mình lại làm như này nhé. :D
            $start = request()->get('start');
            $length = request()->get('length');
            $search = request()->get('search')['value'];
            $sort = request()->get('order')[0];
           // Check xem người dùng có sort or search trên table không.
            if (!empty($sort) || !empty($search)) {
               // Dùng để sort cho đúng column mình cần.
                switch ($sort['column']) {
                    case 1:
                        $sort['column'] = ['pay_date'];
                        break;
                    case 2:
                        $sort['column'] = ['status'];
                        break;
                    case 4:
                    case 5:
                        $sort['column'] = ['value'];
                        break;
                    case 6:
                    case 7:
                        $sort['column'] = ['vnd_value'];
                        break;
                    default:
                        $sort['column'] = NULL;
                        break;
                }
                $items = $this->ItemRepo->getItems($start, $length, $sort, $search);
            }
            else {
                $items = $this->ItemRepo->getItems($start, $length);
            }
            $data = $this->ItemRepo->prepareItemsDataForDataTable($items, $start);
            return [
                "recordsTotal" => $this->ItemRepo->getTotalItem($type), // count toàn bộ items
                "recordsFiltered" => $this->ItemRepo->getTotalItem($search), // count toàn bộ item khớp với search data
                'data' => $data, // dữ liệu trả về
            ];
        }
    }




- Tiếp theo mình viết 1 Repository để xử lý logic của các function mình gọi trên controller. Đọan function này rất căn bản nên mình không giải thích gì nhiều


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 public function getitems($offset, $limit, $sort_by, $search) {
        $items = Transaction::skip($offset)->take($limit);
        if (!empty($sort_by['column']) && !empty($sort_by['dir'])) {
            if (is_array($sort_by['column'])) {
                foreach ($sort_by['column'] as $key => $value) {
                    $items->orderBy($value, $sort_by['dir']);
                }
            }
            else {
                $items->orderBy($sort_by, $sort_by['dir']);
            }
        }
        if(!empty($search)) {
            $items->where('description', 'LIKE', "%{$search}%");
            $items->orWhere('status', '=', $search);
            $items->orWhere('trans_type', '=', $search);
        }
        return $items->get();
    }
    public function getTotalItems($search = NULL) {
        if (!empty($search)) {
            $items = Items::where('description', 'LIKE', "%{$search}%")
            ->orWhere('status', '=', $search)->orWhere('trans_type', '=', $search)->count();
        }
        else $items = Items::count();
        return $items;
    }

   // Đây là function chuẩn bị data để show ra cho chính xác những thứ bạn cần. Ví dụ như datetime, show bao nhiêu kí tự là vừa cho description. Tùy vào mục đích của bạn muốn làm gì

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
    public function prepareitemsDataForDataTable($items, $start) {
        $datas  = [];
        foreach ($items as $key => $item) {
            $data[0] = $start + $key + 1;
            $data[1] = date('d-M-Y', $item->pay_date);
            $data[2] = strlen($item->description) > 70 ? substr($item->description,0,70)."..." : $item->description;
            $data[3] = ($item->trans_type == 'dr') ? $item->usd_value_format : '';
            $data[4] = ($item->trans_type == 'cr') ? $item->usd_value_format : '';
            $data[5] = ($item->trans_type == 'dr') ? $item->vnd_value_format : '';
            $data[6] = ($item->trans_type == 'cr') ? $item->vnd_value_format : '';
            $data[7] = $item->id;
            $datas[] = $data;
        }
        return $datas;
    }
Và đây là thành quả mình đạt được

OK. Như vậy là đã xong baì hướng dẫn. Chúc các bạn thành công! Hãy để lại comment nếu có thắc mắc gì nhé. Mình sẽ trả lời nếu có thời gian.

Nhận xét

Bài đăng phổ biến từ blog này

Upload và remove hình ảnh trong laravel

Chuyển đổi HTML sang PDF sử dụng Javascript

Mã hóa dữ liệu trong Database