DataTable là gì
DataTables là một plug-in mã nguồn mở cho thư viện jQuery giúp nâng cao khả năng tương tác cho các bảng HTML thông thường. Nó cung cấp các tính năng nâng cao như phân trang, tìm kiếm tức thì và sắp xếp dữ liệu chỉ với một dòng mã JavaScriptChuẩn bị môi trường
Để sử dụng DataTables, bạn cần tích hợp thư viện vào project. Bạn có thể sử dụng CDN để nhanh chóng bắt đầu.
Thêm vào file _Layout.cshtml hoặc trực tiếp vào View:
<link rel="stylesheet" href="https://cdn.datatables.net/2.3.7/css/dataTables.dataTables.min.css" />
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://cdn.datatables.net/2.3.7/js/dataTables.min.js"></script>
Cài đặt cơ bản
Giả sử bạn có table HTML với id = 'productTable' như sau:<table id="productTable" class="display">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
<th>Category</th>
<th>Stock</th>
<th>Rating</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Apple</td>
<td>$10</td>
<td>Fruit</td>
<td>150</td>
<td>4.5</td>
<td><span class="badge bg-success">In Stock</span></td>
</tr>
<tr>
<td>Milk</td>
<td>$20</td>
<td>Dairy</td>
<td>80</td>
<td>4.8</td>
<td><span class="badge bg-success">In Stock</span></td>
</tr>
<tr>
<td>Orange</td>
<td>$8</td>
<td>Fruit</td>
<td>200</td>
<td>4.3</td>
<td><span class="badge bg-success">In Stock</span></td>
</tr>
<tr>
<td>Cheese</td>
<td>$15</td>
<td>Dairy</td>
<td>45</td>
<td>4.6</td>
<td><span class="badge bg-warning">Low Stock</span></td>
</tr>
<tr>
<td>Banana</td>
<td>$5</td>
<td>Fruit</td>
<td>300</td>
<td>4.4</td>
<td><span class="badge bg-success">In Stock</span></td>
</tr>
<tr>
<td>Yogurt</td>
<td>$12</td>
<td>Dairy</td>
<td>120</td>
<td>4.7</td>
<td><span class="badge bg-success">In Stock</span></td>
</tr>
<tr>
<td>Carrot</td>
<td>$6</td>
<td>Vegetable</td>
<td>250</td>
<td>4.2</td>
<td><span class="badge bg-success">In Stock</span></td>
</tr>
<tr>
<td>Butter</td>
<td>$18</td>
<td>Dairy</td>
<td>60</td>
<td>4.9</td>
<td><span class="badge bg-success">In Stock</span></td>
</tr>
<tr>
<td>Broccoli</td>
<td>$7</td>
<td>Vegetable</td>
<td>100</td>
<td>4.1</td>
<td><span class="badge bg-danger">Out of Stock</span></td>
</tr>
<tr>
<td>Cream</td>
<td>$25</td>
<td>Dairy</td>
<td>35</td>
<td>4.8</td>
<td><span class="badge bg-warning">Low Stock</span></td>
</tr>
<tr>
<td>Grapes</td>
<td>$12</td>
<td>Fruit</td>
<td>180</td>
<td>4.6</td>
<td><span class="badge bg-success">In Stock</span></td>
</tr>
<tr>
<td>Spinach</td>
<td>$4</td>
<td>Vegetable</td>
<td>220</td>
<td>4.3</td>
<td><span class="badge bg-success">In Stock</span></td>
</tr>
<tr>
<td>Cheese Spread</td>
<td>$22</td>
<td>Dairy</td>
<td>50</td>
<td>4.5</td>
<td><span class="badge bg-warning">Low Stock</span></td>
</tr>
<tr>
<td>Watermelon</td>
<td>$15</td>
<td>Fruit</td>
<td>90</td>
<td>4.7</td>
<td><span class="badge bg-success">In Stock</span></td>
</tr>
<tr>
<td>Tomato</td>
<td>$5</td>
<td>Vegetable</td>
<td>310</td>
<td>4.2</td>
<td><span class="badge bg-success">In Stock</span></td>
</tr>
</tbody>
</table>
Việc kích hoạt DataTables chỉ tốn đúng 1 dòng code JavaScript.
$(document).ready(function () {
$('#productTable').DataTable();
});
Load dữ liệu động với Ajax
Với các ứng dụng thực tế, việc tách biệt giao diện và dữ liệu thông qua Ajax sẽ giúp trang web tải nhanh hơn và trải nghiệm người dùng mượt mà hơn.DataTables yêu cầu dữ liệu trả về thường nằm trong một object có chứa mảng (mặc định là thuộc tính data).
[HttpGet]
public IActionResult GetProducts()
{
var products = new[] {
new { id = 1, name = "Apple", category = "Fruit", price = 10m, stock = 150, ... },
// ... các sản phẩm khác
};
// Phải bọc trong object { data = ... }
return Json(new { data = products });
}
Chỉ định nghĩa Header cho table:
<table id="ajaxDataTable" class="display compact">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Category</th>
<th>Price</th>
<th>Stock</th>
<th>Rating</th>
<th>Status</th>
<th>Date Added</th>
<th>Supplier</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
Load data:
$(document).ready(function () {
var table = null;
// Function to get status badge HTML
function getStatusBadge(status) {
var badgeClass = '';
if (status === 'In Stock') {
badgeClass = 'bg-success';
} else if (status === 'Low Stock') {
badgeClass = 'bg-warning';
} else if (status === 'Out of Stock') {
badgeClass = 'bg-danger';
}
return '<span class="badge ' + badgeClass + '">' + status + '</span>';
}
// Function to load data via Ajax
function loadData() {
$('#loadingIndicator').show();
$.ajax({
url: '/Home/GetProducts',
type: 'GET',
dataType: 'json',
success: function (response) {
if (table) {
table.destroy();
}
// Clear tbody
$('#ajaxDataTable tbody').empty();
// Populate table with data
$.each(response.data, function (index, product) {
var row = $('<tr>').append(
$('<td>').text(product.id),
$('<td>').text(product.name),
$('<td>').text(product.category),
$('<td>').text('$' + product.price),
$('<td>').text(product.stock),
$('<td>').text(product.rating),
$('<td>').html(getStatusBadge(product.status)),
$('<td>').text(product.dateAdded),
$('<td>').text(product.supplier)
);
$('#ajaxDataTable tbody').append(row);
});
// Reinitialize DataTable
table = $('#ajaxDataTable').DataTable({
paging: true,
pageLength: 10,
lengthChange: true,
searching: true,
ordering: true,
info: true,
responsive: false
});
$('#loadingIndicator').hide();
},
error: function (xhr, status, error) {
console.error('Error loading data:', error);
$('#loadingIndicator').hide();
alert('Error loading data from server. Please try again.');
}
});
}
// Load data on page load
loadData();
// Reload button click handler
$('#reloadBtn').click(function () {
loadData();
});
});
Tối ưu hóa với Server-side Processing
Chúng ta sẽ nâng cấp lên Server-side Processing: Client chỉ yêu cầu 10 dòng, Server chỉ trả về đúng 10 dòng đó
Cơ chế hoạt động
Khi bật chế độ serverSide: true, mỗi khi bạn chuyển trang, tìm kiếm hoặc sắp xếp, DataTables sẽ gửi một request kèm theo các tham số:
- draw: Số thứ tự request (để tránh xử lý nhầm dữ liệu cũ).
- start: Vị trí dòng bắt đầu (ví dụ: trang 2, mỗi trang 10 dòng thì start = 10).
- length: Số lượng dòng cần lấy.
- search[value]: Từ khóa tìm kiếm.
Chúng ta xây dựng Search model:
public class DataTableRequest
{
public int Draw { get; set; }
public int Start { get; set; }
public int Length { get; set; }
public Search Search { get; set; } = new Search();
public List<Order> Order { get; set; } = new List<Order>();
}
public class Search {
public string Value { get; set; }
}
Hàm Get Product:
[HttpPost]
public IActionResult GetProductsServerSide([FromForm] DataTableRequest request)
{
// Sample data source
var allProducts = new List<ProductDto>
{
new ProductDto { Id = 1, Name = "Apple", Category = "Fruit", Price = 10m, Stock = 150, Rating = 4.5, Status = "In Stock", DateAdded = "2024-01-15", Supplier = "Fresh Farms Inc" },
new ProductDto { Id = 2, Name = "Milk", Category = "Dairy", Price = 20m, Stock = 80, Rating = 4.8, Status = "In Stock", DateAdded = "2024-01-14", Supplier = "Dairy Corp" },
//...
new ProductDto { Id = 15, Name = "Potatoes", Category = "Vegetable", Price = 8m, Stock = 400, Rating = 4.5, Status = "In Stock", DateAdded = "2024-01-01", Supplier = "Root Vegetables Inc" },
new ProductDto { Id = 16, Name = "Watermelon", Category = "Fruit", Price = 15m, Stock = 90, Rating = 4.7, Status = "In Stock", DateAdded = "2023-12-31", Supplier = "Melon Farms" },
new ProductDto { Id = 17, Name = "Broccoli Sprouts", Category = "Vegetable", Price = 9m, Stock = 60, Rating = 4.2, Status = "In Stock", DateAdded = "2023-12-30", Supplier = "Sprout Factory" },
new ProductDto { Id = 18, Name = "Cheddar Cheese", Category = "Dairy", Price = 22m, Stock = 50, Rating = 4.8, Status = "In Stock", DateAdded = "2023-12-29", Supplier = "Cheese Masters" },
new ProductDto { Id = 19, Name = "Strawberry", Category = "Fruit", Price = 14m, Stock = 110, Rating = 4.6, Status = "In Stock", DateAdded = "2023-12-28", Supplier = "Berry Bliss" },
new ProductDto { Id = 20, Name = "Kale", Category = "Vegetable", Price = 5m, Stock = 180, Rating = 4.3, Status = "In Stock", DateAdded = "2023-12-27", Supplier = "Green Leafy Co" }
};
var query = allProducts.AsQueryable();
var totalRecords = allProducts.Count;
// Search logic
if (!string.IsNullOrEmpty(request.Search?.Value))
{
var searchValue = request.Search.Value.ToLower();
query = query.Where(x => x.Name.ToLower().Contains(searchValue)
|| x.Category.ToLower().Contains(searchValue)
|| x.Supplier.ToLower().Contains(searchValue));
}
var filteredRecords = query.Count();
// Sorting logic
if (request.Order != null && request.Order.Count > 0)
{
var orderColumn = request.Order[0].Column;
var orderDir = request.Order[0].Dir.ToLower() == "desc" ? 1 : 0;
query = orderColumn switch
{
0 => orderDir == 1 ? query.OrderByDescending(x => x.Id) : query.OrderBy(x => x.Id),
1 => orderDir == 1 ? query.OrderByDescending(x => x.Name) : query.OrderBy(x => x.Name),
2 => orderDir == 1 ? query.OrderByDescending(x => x.Category) : query.OrderBy(x => x.Category),
3 => orderDir == 1 ? query.OrderByDescending(x => x.Price) : query.OrderBy(x => x.Price),
4 => orderDir == 1 ? query.OrderByDescending(x => x.Stock) : query.OrderBy(x => x.Stock),
5 => orderDir == 1 ? query.OrderByDescending(x => x.Rating) : query.OrderBy(x => x.Rating),
_ => query.OrderBy(x => x.Id)
};
}
// Pagination
var data = query.Skip(request.Start).Take(request.Length).ToList();
var response = new DataTableResponse<ProductDto>
{
Draw = request.Draw,
RecordsTotal = totalRecords,
RecordsFiltered = filteredRecords,
Data = data
};
return Json(response);
}
Update hàm lấy data từ FrontEnd, chú ý property: "serverSide": true
$(document).ready(function () {
var table = $('#serverSideTable').DataTable({
"processing": true,
"serverSide": true,
"ajax": {
"url": "/Home/GetProductsServerSide",
"type": "POST",
"error": function (xhr, error, thrown) {
console.error('Error:', error);
}
},
"columns": [
{ "data": "id" },
{ "data": "name" },
{ "data": "category" },
{ "data": "price", "render": function (data) { return '$' + data.toFixed(2); } },
{ "data": "stock" },
{ "data": "rating" },
{
"data": "status",
"render": function (data) {
var badgeClass = '';
if (data === 'In Stock') {
badgeClass = 'bg-success';
} else if (data === 'Low Stock') {
badgeClass = 'bg-warning';
} else if (data === 'Out of Stock') {
badgeClass = 'bg-danger';
}
return '<span class="badge ' + badgeClass + '">' + data + '</span>';
}
},
{ "data": "dateAdded" },
{ "data": "supplier" }
],
"pageLength": 10,
"lengthChange": true,
"searching": true,
"ordering": true,
"info": true,
"paging": true,
"language": {
"processing": "Processing...",
"paginate": {
"first": "First",
"last": "Last",
"next": "Next",
"previous": "Previous"
}
}
});
});
Nhận xét
Đăng nhận xét