Kotchasan PHP Framework

การสร้าง 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 จะมีการทำงานดังนี้

  1. ป้องกันการ submit แบบปกติด้วย preventDefault()
  2. ตรวจสอบความถูกต้องของข้อมูล (Validation)
  3. สร้าง FormData object เพื่อเก็บข้อมูลทั้งหมดจาก form
  4. สร้าง XMLHttpRequest สำหรับส่งข้อมูลแบบ AJAX
  5. แสดง progress bar และ disable ปุ่ม submit
  6. ส่งข้อมูลไปยัง 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)
    1.   แสดงข้อความสำเร็จ
    2.   รีเซ็ต form
    3.   ซ่อน progress bar
  • กรณีเกิดข้อผิดพลาด
    1.   แสดงข้อความแจ้งเตือน
    2.   enable ปุ่ม submit
    3.   ซ่อน 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 ทำให้ประสบการณ์การใช้งานดีขึ้น