การสร้าง Upload Form ด้วย AJAX และ JavaScript
บทความนี้จะอธิบายวิธีการสร้าง Upload Form ที่ใช้ AJAX เพื่อให้สามารถอัพโหลดไฟล์โดยไม่ต้อง refresh หน้าเว็บ พร้อมแสดงความคืบหน้าของการอัพโหลด
โครงสร้าง HTML Form
เริ่มต้นด้วยการสร้าง form ที่มี enctype เป็น "multipart/form-data" ซึ่งจำเป็นสำหรับการอัพโหลดไฟล์ ภายใน form ประกอบด้วย
- Title สำหรับกรอกชื่อไฟล์หรือหัวข้อ
- Description สำหรับกรอกคำอธิบายเพิ่มเติม
- Category dropdown สำหรับเลือกประเภทของไฟล์
- File Input สำหรับเลือกไฟล์ที่ต้องการอัพโหลด
- Progress Bar แสดงความคืบหน้าการอัพโหลด
- Submit Button ปุ่มสำหรับส่งข้อมูล
<form id="uploadForm" enctype="multipart/form-data">
<div class="form-group">
<label for="title">Title:</label>
<input type="text" id="title" name="title" required>
</div>
<div class="form-group">
<label for="description">Description:</label>
<textarea id="description" name="description" rows="3"></textarea>
</div>
<div class="form-group">
<label for="category">Category:</label>
<select id="category" name="category">
<option value="">Select category</option>
<option value="documents">Documents</option>
<option value="images">Images</option>
<option value="videos">Videos</option>
</select>
</div>
<div class="form-group">
<label for="fileInput">File:</label>
<input type="file" id="fileInput" name="file" required>
<small class="file-info">Max file size: 10MB</small>
</div>
<div class="progress-container" style="display: none;">
<div class="progress-bar" id="progressBar">
<div class="progress" style="width: 0%"></div>
</div>
<div class="progress-text">0%</div>
</div>
<button type="submit" id="submitBtn">Upload</button>
</form>
การจัดการ Form Submit
เมื่อผู้ใช้กดปุ่ม Submit จะมีการทำงานดังนี้
- ป้องกันการ submit แบบปกติด้วย preventDefault()
- ตรวจสอบความถูกต้องของข้อมูล (Validation)
- สร้าง FormData object เพื่อเก็บข้อมูลทั้งหมดจาก form
- สร้าง XMLHttpRequest สำหรับส่งข้อมูลแบบ AJAX
- แสดง progress bar และ disable ปุ่ม submit
- ส่งข้อมูลไปยัง server
/**
* File Upload Handler
* Handles file upload using Ajax with progress tracking and validation
*/
document.getElementById('uploadForm').addEventListener('submit', function(e) {
e.preventDefault();
// Validate form
if (!validateForm()) {
return;
}
// Get form elements
const fileInput = document.getElementById('fileInput');
const title = document.getElementById('title').value;
const description = document.getElementById('description').value;
const category = document.getElementById('category').value;
const submitBtn = document.getElementById('submitBtn');
const progressContainer = document.querySelector('.progress-container');
const progressBar = document.querySelector('.progress');
const progressText = document.querySelector('.progress-text');
// Create FormData object
const formData = new FormData();
formData.append('file', fileInput.files[0]);
formData.append('title', title);
formData.append('description', description);
formData.append('category', category);
// Create XMLHttpRequest object
const xhr = new XMLHttpRequest();
// Show progress container and disable submit button
progressContainer.style.display = 'block';
submitBtn.disabled = true;
/**
* Track upload progress
* @param {ProgressEvent} e - Progress event object
*/
xhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable) {
const percentComplete = Math.round((e.loaded / e.total) * 100);
progressBar.style.width = percentComplete + '%';
progressText.textContent = percentComplete + '%';
}
});
/**
* Handle successful upload
* @param {Event} e - Load event object
*/
xhr.addEventListener('load', function(e) {
submitBtn.disabled = false;
if (xhr.status === 200) {
showMessage('success', 'File uploaded successfully!');
resetForm();
} else {
showMessage('error', 'Upload failed. Status: ' + xhr.status);
}
progressContainer.style.display = 'none';
});
/**
* Handle upload error
* @param {Event} e - Error event object
*/
xhr.addEventListener('error', function(e) {
submitBtn.disabled = false;
showMessage('error', 'An error occurred during upload.');
progressContainer.style.display = 'none';
});
// Configure and send request
xhr.open('POST', '/upload.php', true);
xhr.send(formData);
});
/**
* Validate form inputs
* @returns {boolean} - Validation result
*/
function validateForm() {
const title = document.getElementById('title').value;
const fileInput = document.getElementById('fileInput');
const file = fileInput.files[0];
if (!title.trim()) {
showMessage('error', 'Please enter a title');
return false;
}
if (!file) {
showMessage('error', 'Please select a file');
return false;
}
// Check file size (10MB limit)
if (file.size > 10 * 1024 * 1024) {
showMessage('error', 'File size must be less than 10MB');
return false;
}
return true;
}
/**
* Show message to user
* @param {string} type - Message type (success/error)
* @param {string} message - Message text
*/
function showMessage(type, message) {
alert(message); // You can replace this with a better UI notification
}
/**
* Reset form to initial state
*/
function resetForm() {
document.getElementById('uploadForm').reset();
document.querySelector('.progress').style.width = '0%';
document.querySelector('.progress-text').textContent = '0%';
}
การติดตามความคืบหน้า
ระหว่างการอัพโหลด จะมีการติดตามความคืบหน้าผ่าน event "progress" ของ XMLHttpRequest
- คำนวณเปอร์เซ็นต์จาก e.loaded และ e.total
- อัพเดต progress bar และข้อความแสดงเปอร์เซ็นต์
- แสดงผลแบบ real-time ให้ผู้ใช้เห็น
การตรวจสอบข้อมูล
ฟังก์ชัน validateForm() จะตรวจสอบ
- Title ต้องไม่เป็นค่าว่าง
- ต้องมีการเลือกไฟล์
- ขนาดไฟล์ต้องไม่เกิน 10MB
การจัดการผลลัพธ์
หลังจากอัพโหลดเสร็จ จะมีการจัดการตามสถานะ
- กรณีสำเร็จ (status 200)
- แสดงข้อความสำเร็จ
- รีเซ็ต form
- ซ่อน progress bar
- กรณีเกิดข้อผิดพลาด
- แสดงข้อความแจ้งเตือน
- enable ปุ่ม submit
- ซ่อน progress bar
CSS Styling
การจัดรูปแบบหน้าตาของ form ใช้ CSS โดยมีการจัดการ
- จัดวาง layout ของ form elements
- ตกแต่ง progress bar ให้สวยงาม
- ปรับแต่ง input fields ให้ใช้งานง่าย
- สร้าง responsive design
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
}
.form-group input[type="text"],
.form-group textarea,
.form-group select {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.progress-container {
margin: 15px 0;
}
.progress-bar {
width: 100%;
height: 20px;
background-color: #f0f0f0;
border-radius: 10px;
overflow: hidden;
}
.progress {
height: 100%;
background-color: #4CAF50;
transition: width 0.3s ease-in-out;
}
.file-info {
display: block;
color: #666;
font-size: 12px;
margin-top: 5px;
}
button {
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
button:disabled {
background-color: #cccccc;
cursor: not-allowed;
}
การนำไปใช้งาน
ในการนำไปใช้งานจริง ต้องมีการสร้างไฟล์ PHP (upload.php) เพื่อรับและจัดการไฟล์ที่อัพโหลด โดยควรมีการตรวจสอบ
- ประเภทไฟล์ที่อนุญาต
- ขนาดไฟล์สูงสุด
- พื้นที่จัดเก็บที่เหลือ
- สิทธิ์ในการเข้าถึง
สรุป
การสร้าง Upload Form ด้วย AJAX ช่วยให้ผู้ใช้สามารถอัพโหลดไฟล์ได้โดยไม่ต้อง refresh หน้าเว็บ และสามารถเห็นความคืบหน้าของการอัพโหลดได้ทันที การใช้ JavaScript ช่วยในการตรวจสอบข้อมูลและจัดการ UI ทำให้ประสบการณ์การใช้งานดีขึ้น