Quản lý Form表单 và Chế độ Chỉnh sửa với jQuery
Việc xây dựng các bảng dữ liệu có khả năng tương tác cao là một yêu cầu phổ biến trong phát triển frontend. Dưới đây là hướng dẫn cách tổ chức cấu trúc thư mục và triển khai các chức năng như chọn hàng, bật chế độ chỉnh sửa và mở rộng plugin.
1. Cấu trúc HTML và CSS cơ bản
Để đảm bảo tính bảo trì, mã nguồn cần được tổ chức rõ ràng. Các file CSS và JS nên được tách riêng. Dưới đây là khung HTML chính cho bảng dữ liệu:
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<title>Quản lý Dữ liệu Server</title>
<style>
.btn-action {
background-color: #ccc;
padding: 10px;
color: #fff;
text-decoration: none;
cursor: pointer;
}
.state-active {
background-color: #ff9800;
}
.editable-cell {
border: 1px dashed #ccc;
}
</style>
</head>
<body>
<div class="toolbar">
<input type="button" onclick="selectAllRows('#actionBtn', '#dataTable');" value="Chọn tất cả" />
<input type="button" onclick="invertSelection('#actionBtn', '#dataTable');" value="Chọn ngược lại" />
<input type="button" onclick="clearSelection('#actionBtn', '#dataTable');" value="Bỏ chọn" />
<a id="actionBtn" class="btn-action" href="javascript:void(0);"
onclick="toggleEditState(this, '#dataTable');">Bật chế độ sửa</a>
</div>
<table style="margin-top: 20px;" border="1">
<thead>
<tr>
<th>Chọn</th>
<th>Tên Host</th>
<th>Cổng</th>
<th>Dịch vụ</th>
<th>Trạng thái</th>
</tr>
</thead>
<tbody id="dataTable">
<tr>
<td><input type="checkbox" /></td>
<td data-editable="true">server_01</td>
<td>8080</td>
<td data-editable="true" data-type="select" data-source="BIZ_TYPE" data-val="2">Thương mại điện tử</td>
<td data-editable="true" data-type="select" data-source="STATUS_MAP" data-val="1">Đang chạy</td>
</tr>
<tr>
<td><input type="checkbox" /></td>
<td data-editable="true">server_02</td>
<td>8081</td>
<td data-editable="true" data-type="select" data-source="BIZ_TYPE" data-val="3">Giải trí</td>
<td data-editable="true" data-type="select" data-source="STATUS_MAP" data-val="1">Đang chạy</td>
</tr>
</tbody>
</table>
<script src="js/jquery.min.js"></script>
<script src="js/table_manager.js"></script>
</body>
</html>
2. Triển khai Logic JavaScript
Đảm bảo thư viện jQuery gốc được tải trước các script tùy chỉnh. Chúng ta sẽ sử dụng class CSS để xác định trạng thái thay vì chỉ dựa vào thuộc tính.
2.1. Cấu hình dữ liệu và sự kiện
const STATUS_MAP = [
{'id': 1, 'label': "Đang chạy"},
{'id': 2, 'label': "Đã dừng"}
];
const BIZ_TYPE = [
{'id': 1, 'label': "Hội nghị"},
{'id': 2, 'label': "Thương mại điện tử"},
{'id': 3, 'label': "Giải trí"}
];
$(document).ready(function(){
// Xử lý sự kiện click checkbox
$('#dataTable').find('input[type="checkbox"]').on('click', function(){
const row = $(this).closest('tr');
if($("#actionBtn").hasClass('state-active')){
if($(this).is(':checked')){
activateRowEdit(row);
} else {
deactivateRowEdit(row);
}
}
});
});
2.2. Hàm chuyển đổi chế độ chỉnh sửa
Khi người dùng click vào nút bật chế độ sửa, các dòng được chọn sẽ chuyển sang dạng input hoặc select.
function toggleEditState(btn, tableSelector) {
const isEditing = $(btn).hasClass('state-active');
const $table = $(tableSelector);
if (isEditing) {
// Thoát chế độ sửa
$(btn).text('Bật chế độ sửa').removeClass('state-active');
$table.find('tr').each(function(){
if($(this).find('input[type="checkbox"]').is(':checked')){
deactivateRowEdit($(this));
}
});
} else {
// Vào chế độ sửa
$(btn).text('Thoát chế độ sửa').addClass('state-active');
$table.find('tr').each(function(){
if($(this).find('input[type="checkbox"]').is(':checked')){
activateRowEdit($(this));
}
});
}
}
function activateRowEdit(row) {
row.find('td').each(function(){
const cell = $(this);
if(cell.attr('data-editable') === 'true'){
if(cell.attr('data-type') === 'select'){
const sourceKey = cell.attr('data-source');
const currentVal = parseInt(cell.attr('data-val'));
const optionsData = window[sourceKey];
let optionsHtml = '';
$.each(optionsData, function(_, item){
const selected = (item.id === currentVal) ? 'selected' : '';
optionsHtml += `<option value="${item.id}" ${selected}>${item.label}</option>`;
});
cell.html(`<select onchange="bulkUpdate(this);">${optionsHtml}</select>`);
} else {
const text = cell.text().trim();
cell.html(`<input type="text" value="${text}" />`);
}
}
});
}
function deactivateRowEdit(row) {
row.find('td').each(function(){
const cell = $(this);
if(cell.attr('data-editable') === 'true'){
const input = cell.find('input, select').first();
if(input.length){
cell.text(input.val());
}
}
});
}
2.3. Chức năng chọn và sửa hàng loạt
Hỗ trợ phím Ctrl để thay đổi giá trị của nhiều dòng cùng lúc.
let isCtrlPressed = false;
window.onkeydown = function(e){
if(e && e.keyCode === 17) isCtrlPressed = true;
};
window.onkeyup = function(e){
if(e && e.keyCode === 17) isCtrlPressed = false;
};
function bulkUpdate(element) {
if(isCtrlPressed){
const rowIndex = $(element).closest('td').index();
const newValue = $(element).val();
$(element).closest('tr').nextAll().each(function(){
if($(this).find('input[type="checkbox"]').is(':checked')){
const targetSelect = $(this).find('td').eq(rowIndex).find('select');
if(targetSelect.length){
targetSelect.val(newValue);
}
}
});
}
}
function selectAllRows(btn, tableSelector) {
$(tableSelector).find('tr').each(function(){
const cb = $(this).find('input[type="checkbox"]');
if(!cb.is(':checked')){
cb.prop('checked', true);
if($(btn).hasClass('state-active')){
activateRowEdit($(this));
}
}
});
}
function invertSelection(btn, tableSelector) {
$(tableSelector).find('tr').each(function(){
const cb = $(this).find('input[type="checkbox"]');
const isChecked = cb.is(':checked');
cb.prop('checked', !isChecked);
if($(btn).hasClass('state-active')){
if(!isChecked) activateRowEdit($(this));
else deactivateRowEdit($(this));
}
});
}
function clearSelection(btn, tableSelector) {
$(tableSelector).find('tr').each(function(){
const cb = $(this).find('input[type="checkbox"]');
if(cb.is(':checked')){
cb.prop('checked', false);
if($(btn).hasClass('state-active')){
deactivateRowEdit($(this));
}
}
});
}
Thao tác với DOM động
Trong các form tìm kiếm phức tạp, người dùng thường cần thêm hoặc bớt các điều kiện lọc dynamically.
1. Thêm/Xóa phần tử
Sử dụng phương thức clone() để nhân bản cấu trúc HTML và remove() để xóa.
<div id="searchArea">
<div class="search-item">
<span onclick="addSearchField(this)">+</span>
<input type="text" placeholder="Điều kiện">
</div>
</div>
<script>
function addSearchField(elem) {
const newItem = $(elem).parent().clone();
newItem.find('span').text('-').attr('onclick', 'removeSearchField(this)');
newItem.appendTo('#searchArea');
}
function removeSearchField(elem) {
$(elem).parent().remove();
}
</script>
Mở rộng jQuery (Plugins)
jQuery cho phép mở rộng chức năng thông qua cơ chế plugin. Có hai cách chính là mở rộng tĩnh ($.extend) và mở rộng đối tượng ($.fn.extend).
1. jQuery.extend
Dùng để thêm các hàm tiện ích toàn cục.
(function($){
$.extend({
'getVersion': function(){
return '1.0.0';
}
});
})(jQuery);
// Sử dụng: $.getVersion()
2. jQuery.fn.extend
Dùng để thêm phương thức cho các đối tượng jQuery, cho phép chuỗi (chaining).
$.fn.extend({
highlight: function() {
return this.each(function() {
$(this).css('background', 'yellow');
});
}
});
// Sử dụng: $('p').highlight();
3. Plugin xác thực Form
Dưới đây là ví dụ về một plugin đơn giản để validate form đăng ký và đăng nhập dựa trên các thuộc tính HTML.
(function($){
function showError(container, msg){
let errLabel = container.find("label.error-msg");
if(errLabel.length){
errLabel.text(msg);
} else {
container.append(`<label class="error-msg">${msg}</label>`);
}
}
function clearError(container){
container.find("label.error-msg").remove();
}
$.extend({
'validateForm': function(formSelector){
$(formSelector).find('input[type="submit"]').on('click', function(e){
let isValid = true;
$(formSelector).find('input[type="text"], input[type="password"]').each(function(){
const $input = $(this);
const val = $input.val().trim();
const parent = $input.parent();
const label = $input.attr('data-label');
if($input.attr('required') && !val){
isValid = false;
showError(parent, label + ' không được để trống.');
return false;
}
if($input.attr('data-confirm')){
const original = $(formSelector).find("input[name='"+$input.attr('data-confirm')+"']");
if(original.val().trim() !== val){
isValid = false;
showError(parent, 'Mật khẩu xác nhận không khớp.');
return false;
}
}
clearError(parent);
});
if(!isValid) e.preventDefault();
return isValid;
});
}
});
})(jQuery);
Sử dụng Bootstrap Framework
Bootstrap là một framework frontend mã nguồn mở giúp xây dựng giao diện响应式 (responsive) nhanh chóng. Nó cung cấp hệ thống grid, các component CSS và plugin JavaScript.
1. Cấu trúc file
Phiên bản Bootstrap 3 thường bao gồm:
- css: bootstrap.css, bootstrap-theme.css (tùy chọn).
- js: bootstrap.js (yêu cầu jQuery).
- fonts: Glyphicons cho các biểu tượng.
2. Mẫu HTML chuẩn
Khi tích hợp Bootstrap, cần đảm bảo các thẻ meta viewport và compatibility được thiết lập đúng.
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ứng dụng Bootstrap</title>
<link href="css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h1>Xin chào!</h1>
</div>
<script src="js/jquery.min.js"></script>
<script src="js/bootstrap.min.js"></script>
</body>
</html>
Các thẻ meta quan trọng:
viewport: Đảm bảo hiển thị đúng trên thiết bị di động.X-UA-Compatible: Buộc IE sử dụng chế độ render mới nhất.
3. Lưu ý khi sử dụng
Bootstrap cung cấp các class utility giúp layout nhanh chóng. Tuy nhiên, để tùy biến sâu, developer cần hiểu rõ hệ thống grid 12 cột và cách ghi đè CSS khi cần thiết. Nên tham khảo tài liệu chính thức để sử dụng đúng các component như Modal, Dropdown hay Navbar.