การใช้งาน Angular ร่วมกับ Datatables เรียกใช้ข้อมูลจาก PHP และ MySQL แบบ Server-side

วันที่: 18 ก.พ. 2565 00:42 น.

การใช้งาน Angular ร่วมกับ Datatables เรียกใช้ข้อมูลจาก PHP และ MySQL แบบ Server-side

DataTables server-side คือการที่ระบบไปเรียกข้อมูลจากฝั่ง server เท่าที่จำเป็นต่อการแสดงผลในแต่ละครั้งครับ ซึ่งหากยังสงสัยว่า ทำไมต้องเรียกทีละน้อยๆมาล่ะ ในเมื่อความสามารถของ datatables ก็สามารถแบ่งหน้าให้อยู่แล้ว ? ก็ใช่ครับ ถ้าข้อมูลมีไม่มาก แต่ให้ลองนึกถึงข้อมูลหลายแสน record การดึงมาแสดงในครั้งเดียวนั้นจะใช้เวลานานมาก หรืออาจทำให้ server ล่มได้เลย เพราะงั้นจึงเกิดเจ้าตัว server-side นี่ล่ะครับ

เอาง่าย ๆ คือ จะดึงข้อมูลมาทีละ 10 50 หรือ 100 ต่อหน้านั้น ๆ หากคลิกหน้าถัดไป ค่อยดึงมาแสดงใหม่ แต่การใช้งานร่วมกับ Angular เขาใช้ยังไง จะพาทำในบทความนี้ครับ

ถ้ามีทั้งสองอย่างแล้ว ก็มาเริ่มกันเลย 

ไฟล์ app.component.html จะมีโค้ดดังนี้

<div class="container pt-5">
  <table datatable [dtOptions]="dtOptions" class="table table-hover table-bordered">
    <thead>
      <tr>
        <th>ID</th>
        <th>First name</th>
        <th>Last name</th>
      </tr>
    </thead>
    <tbody *ngIf="persons?.length != 0">
      <tr *ngFor="let person of persons">
        <td>{{ person.id }}</td>
        <td>{{ person.firstName }}</td>
        <td>{{ person.lastName }}</td>
      </tr>
    </tbody>
    <tbody *ngIf="persons?.length == 0">
      <tr>
        <td colspan="3" class="no-data-available">No data!</td>
      </tr>
    </tbody>
  </table>
</div>

ในไฟล์ app.component.ts จะมีโค้ดดังนี้

import { HttpClient } from '@angular/common/http';
import { Component } from '@angular/core';

class DataTablesResponse {
  data: any[] | undefined;
  draw: number | undefined;
  recordsFiltered: number | undefined;
  recordsTotal: number | undefined;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})

export class AppComponent {
  title = 'angular-datatables';
  dtOptions: DataTables.Settings = {};
  persons: any = [];

  constructor(private http: HttpClient) { }

  ngOnInit(): void {
    this.dtOptions = {
      pagingType: 'full_numbers',
      pageLength: 10,
      serverSide: true,
      processing: true,
      ajax: (dataTablesParameters: any, callback) => {
        this.http
          .post<DataTablesResponse>(
            'http://localhost/get_data.php',
            dataTablesParameters, {}
          ).subscribe(res => {
            this.persons = res.data;
            callback({
              recordsTotal: res.recordsTotal,
              recordsFiltered: res.recordsFiltered,
              data: []
            });
          });
      },
      columns: [{ data: 'id' }, { data: 'firstName' }, { data: 'lastName' }]
    };
  }
}

ตรง dataTablesParameters นั้น หากเรา log ออกมาดูจะเห็นได้ว่า มีการส่งข้อมูลอะไรไปฝั่ง server บ้าง ซึ่งผม log มาไว้ให้ละ จะมีตามนี้

{
    "draw": 1,
    "columns": [
        {
            "data": "id",
            "name": "",
            "searchable": true,
            "orderable": true,
            "search": {
                "value": "",
                "regex": false
            }
        },
        {
            "data": "firstName",
            "name": "",
            "searchable": true,
            "orderable": true,
            "search": {
                "value": "",
                "regex": false
            }
        },
        {
            "data": "lastName",
            "name": "",
            "searchable": true,
            "orderable": true,
            "search": {
                "value": "",
                "regex": false
            }
        }
    ],
    "order": [
        {
            "column": 0,
            "dir": "asc"
        }
    ],
    "start": 0,
    "length": 10,
    "search": {
        "value": "",
        "regex": false
    }
}

ถ้าเห็นแบบนี้แล้ว เราก็สามารถนำ params ต่าง ๆ นี้ไปเรียกใช้งานได้แล้ว ไม่ว่าจะเป็น คำค้น จำนวนที่แสดงในแต่ละหน้า การเรียงลำดับ ชื่อคอลัมน์ที่ใช้แสดงผล คงพอนึกออกแล้วว่าเราจะใช้งานยังไงใช่ไหมครับ มาดูฝั่ง server กัน

สร้างฐานข้อมูลก่อน เอาชื่ออะไรก็ได้ตามใจเลย แล้วสร้างตารางตามนี้ครับ

CREATE TABLE `persons` (
  `id` int(11) NOT NULL,
  `firstName` varchar(255) DEFAULT NULL,
  `lastName` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ส่วนข้อมูลที่ใช้ insert ผมจะอัพไว้ให้ดาวน์โหลดท้ายบทความนี้

ไฟล์ get_data.php จะมีโค้ดดังนี้

<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token , Authorization');

$data = file_get_contents('php://input');
if ($data == '')
	return;

$data_array = json_decode($data);

$serverName = "localhost";
$userName = "root";
$userPassword = "";
$dbName = "mydatabase";

$conn = new mysqli($serverName, $userName, $userPassword, $dbName);
$sql = "SELECT * FROM persons";

$stmt = $conn->prepare($sql);
$stmt->execute();
$result = $stmt->store_result();
$recordsTotal = $stmt->num_rows;
$stmt->close();

if ($data_array->search->value != '') {
	$search_value = "%{$data_array->search->value}%";
	$sql .= " WHERE firstName LIKE ? OR lastName LIKE ? LIMIT $data_array->start, $data_array->length";
	$stmt = $conn->prepare($sql);
	$stmt->bind_param('ss', $search_value, $search_value); //   s - string, b - blob, i - int, etc
} else {
	$sql .= " LIMIT $data_array->start, $data_array->length";
	$stmt = $conn->prepare($sql);
}

$stmt->execute();
$result = $stmt->get_result();

$data_return = array(
	'draw' => 0,
	'recordsTotal' => 0,
	'recordsFiltered' => 0,
	'data' => array()
);

if ($result->num_rows === 0) {
	echo json_encode($data_return);
	return;
}

$data_return['draw'] = 0;
$data_return['recordsTotal'] = $recordsTotal;
$data_return['recordsFiltered'] = $recordsTotal;
while ($rs = $result->fetch_assoc()) {
	$data_return['data'][] = array(
		'id' => $rs['id'],
		'firstName' => $rs['firstName'],
		'lastName' => $rs['lastName']
	);
}
echo json_encode($data_return);
$stmt->close();
$conn->close();

ผลลัพธ์ที่ได้ จะหน้าตาแบบนี้แหละครับ

ลองนำไปใช้งานครับ ดาวน์โหลดโค้ดทั้งหมดได้ที่นี่

เรื่องอื่น ๆ ที่เกี่ยวข้อง