Validation phía client
Form validation là quá trình kiểm tra dữ liệu người dùng nhập vào trước khi gửi lên server. Validation phía client giúp phản hồi nhanh hơn và cải thiện UX.
Có hai hướng tiếp cận:
- HTML5 built-in:
required,type="email",minlength,pattern— đơn giản nhưng khó tuỳ biến - JavaScript thuần: kiểm tra bằng code, hiển thị lỗi tùy ý
<form id="reg-form" novalidate>
<h2>Đăng ký tài khoản</h2>
<div class="field">
<label for="name">Họ và tên</label>
<input id="name" type="text" placeholder="Nguyễn Văn A" autocomplete="name">
<span class="msg"></span>
</div>
<div class="field">
<label for="email">Email</label>
<input id="email" type="email" placeholder="example@email.com" autocomplete="email">
<span class="msg"></span>
</div>
<div class="field">
<label for="pass">Mật khẩu</label>
<input id="pass" type="password" placeholder="Tối thiểu 8 ký tự">
<div class="strength-bar"><div id="strength"></div></div>
<span class="msg"></span>
</div>
<div class="field">
<label for="pass2">Xác nhận mật khẩu</label>
<input id="pass2" type="password" placeholder="Nhập lại mật khẩu">
<span class="msg"></span>
</div>
<button type="submit" class="submit-btn">Đăng ký</button>
<p id="success" class="success-msg" hidden>✅ Đăng ký thành công!</p>
</form>
* { box-sizing:border-box; font-family:sans-serif; margin:0; padding:0; }
body { background:#f4f6f8; display:flex; justify-content:center; padding:1.5rem; }
form {
background:white; padding:1.75rem; border-radius:10px;
box-shadow:0 2px 12px rgba(0,0,0,.1); width:320px;
}
h2 { margin-bottom:1.25rem; font-size:1.1rem; color:#333; }
.field { margin-bottom:.9rem; }
label { display:block; font-size:.82rem; font-weight:600; color:#555; margin-bottom:.3rem; }
input {
width:100%; padding:.5rem .75rem; border:1.5px solid #ddd;
border-radius:6px; font-size:.9rem; outline:none; transition:border-color .2s;
}
input:focus { border-color:#4472c4; }
input.valid { border-color:#2ecc71; background:#f6fff8; }
input.invalid { border-color:#e74c3c; background:#fff8f8; }
.msg { font-size:.75rem; margin-top:.25rem; display:block; }
.msg.ok { color:#27ae60; }
.msg.err { color:#e74c3c; }
.strength-bar {
height:4px; background:#eee; border-radius:2px;
margin-top:.35rem; overflow:hidden;
}
#strength { height:100%; width:0; border-radius:2px; transition:width .3s, background .3s; }
.submit-btn {
width:100%; padding:.6rem; background:#4472c4; color:white;
border:none; border-radius:6px; font-size:.95rem; cursor:pointer; margin-top:.25rem;
}
.submit-btn:hover { background:#3260ad; }
.success-msg { margin-top:.75rem; text-align:center; color:#27ae60; font-weight:600; font-size:.9rem; }
const rules = {
name(v) { return v.trim().length >= 2 ? '' : 'Họ tên phải có ít nhất 2 ký tự'; },
email(v) { return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v) ? '' : 'Email không hợp lệ'; },
pass(v) {
if (v.length < 8) return 'Mật khẩu tối thiểu 8 ký tự';
if (!/[A-Z]/.test(v)) return 'Cần ít nhất 1 chữ hoa';
if (!/\d/.test(v)) return 'Cần ít nhất 1 chữ số';
return '';
},
pass2(v) { return v === document.getElementById('pass').value ? '' : 'Mật khẩu không khớp'; }
};
function showResult(id, error) {
const input = document.getElementById(id);
const msg = input.parentElement.querySelector('.msg');
if (error) {
input.className = 'invalid';
msg.textContent = error;
msg.className = 'msg err';
} else {
input.className = 'valid';
msg.textContent = '✓';
msg.className = 'msg ok';
}
return !error;
}
// Realtime validation
['name','email','pass','pass2'].forEach(id => {
document.getElementById(id).addEventListener('input', function() {
const err = (rules[id] || (() => ''))(this.value);
if (this.value) showResult(id, err);
// Strength bar for password
if (id === 'pass') {
const v = this.value;
let score = 0;
if (v.length >= 8) score++;
if (/[A-Z]/.test(v)) score++;
if (/\d/.test(v)) score++;
if (/[^A-Za-z0-9]/.test(v)) score++;
const bar = document.getElementById('strength');
const colors = ['#e74c3c','#f39c12','#f1c40f','#2ecc71'];
bar.style.width = score * 25 + '%';
bar.style.background = colors[score - 1] || '#eee';
}
});
});
document.getElementById('reg-form').addEventListener('submit', function(e) {
e.preventDefault();
const valid = ['name','email','pass','pass2'].every(id =>
showResult(id, (rules[id] || (() => ''))(document.getElementById(id).value))
);
if (valid) document.getElementById('success').hidden = false;
});
Bình luận