Đối tượng FileList (trả về bởi input.files) là read-only (chỉ đọc) và bất biến (immutable). Không thể xóa trực tiếp phần tử khỏi FileList bằng JavaScript.
Giải pháp: Chuyển sang Array -> Xử lý -> Gán lại (nếu cần)
Cách 1: Tạo Array mới từ FileList, lọc, dùng Array đó
const fileInput = document.querySelector('input[type="file"][multiple]');
const filesArray = Array.from(fileInput.files); // Chuyển FileList -> Array
// Lọc: ví dụ xóa file index 1, hoặc lọc theo size/name
const filteredFiles = filesArray.filter((file, index) => index !== 1); // Xóa item index 1
// Hoặc: filteredFiles = filesArray.filter(f => f.size < 5*1024*1024); // < 5MB
// Sử dụng filteredFiles cho FormData, upload, hiển thị preview...
const formData = new FormData();
filteredFiles.forEach(file => formData.append("files[]", file));
Cách 2: DataTransfer API (Tạo FileList mới) - Để gán lại vào input.files
Nếu bắt buộc phải gán FileList mới vào input.files (ví dụ: hiển thị lại cho user, submit form gốc), dùng DataTransfer (hỗ trợ tốt trên Chrome, Edge, Firefox mới; Safari hạn chế).
const fileInput = document.querySelector('input[type="file"][multiple]');
const dt = new DataTransfer(); // Tạo DataTransfer rỗng
// Lọc file từ FileList gốc
Array.from(fileInput.files).forEach((file, index) => {
if (index !== 1) { // Giữ lại trừ index 1
dt.items.add(file); // Thêm file vào DataTransfer
}
});
// Gán FileList MỚI vào input (Chỉ hoạt động trên trình duyệt hiện đại, KHÔNG phải mọi nơi)
fileInput.files = dt.files;
// Lưu ý: fileInput.files = dt.files KHÔNG hoạt động trên Safari, một số mobile browser.
// Cách an toàn: Dùng FormData từ filteredFiles để submit qua AJAX/Fetch.
Cách 3: Quản lý state riêng (React/Vue/Angular/Vanilla State) - Best Practice
Không phụ thuộc vào input.files. Lưu danh sách file đã chọn trong state (Array), render UI từ state, xóa từ state, submit từ state.
// Vanilla JS State Pattern
let selectedFiles = []; // State quản lý file
fileInput.addEventListener("change", (e) => {
selectedFiles = Array.from(e.target.files); // Cập nhật state
renderFileList(); // Render UI từ state
});
function removeFile(index) {
selectedFiles.splice(index, 1); // Xóa khỏi state
renderFileList(); // Cập nhật UI
}
function submitFiles() {
const formData = new FormData();
selectedFiles.forEach(f => formData.append("files[]", f));
fetch("/upload", { method: "POST", body: formData });
}
Tóm tắt
| Cách | Ưu điểm | Nhược điểm | Phù hợp |
|---|---|---|---|
Array.from(files).filter(...) | Đơn giản, an toàn, mọi trình duyệt | Không gán lại được input.files | Xử lý, preview, upload qua FormData/Fetch |
DataTransfer + input.files = dt.files | Cập nhật input.files thật | Không hỗ trợ Safari, một số mobile; phức tạp | Cần submit form gốc (non-AJAX) |
| Quản lý State riêng (Array) | Kiểm soát hoàn toàn, framework-friendly, tách UI/logic | Viết code nhiều hơn | Best Practice cho App thực tế |
Kết luận: FileList bất biến. Hãy chuyển sang Array (Array.from(input.files)), lọc/sửa trên Array, sau đó dùng Array đó để tạo FormData upload (AJAX/Fetch) hoặc render UI. Tránh gán lại input.files do hỗ trợ trình duyệt không đồng đều.