Control Upload File
Bài đăng này đã không được cập nhật trong 6 năm
Trong bài viết này, mình sẽ sử dụng ví dụ về upload file ảnh để nói về các vấn đề cơ bản về upload file trong java script mà mình tìm hiểu được.
1. Upload single file:
- Đề upload file trong javascript, ta sử dụng class FileReader và sự kiện onload()
- Ta tạo file upload_single_file.html và upload_single_file.js để thực hiện upload và hiển thị 1 file ảnh duy nhất.
- Ta thêm sẵn các thư viện bootstrap và jQuery để tiện sử dụng.
<!DOCTYPE html>
<html>
<head>
<title>UPLOAD SINGLE FILE</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="scripts/upload_single_file.js"></script>
</head>
<body>
<div class="container">
<h2>Upload single file</h2>
<form>
<div class="form-group">
<label>Select single image file</label>
<input type="file" class="form-control" id="fileInput">
</div>
</form>
</div>
<div class="container js-file-list">
</div>
</body>
</html>
$(document).ready(function(){
$('#fileInput').on('change', function() {
var file = $(this)[0].files[0];
var fileReader = new FileReader();
fileReader.onload = function() {
var str = '<div class="col-md-2">' +
'<span class="js-file-name"></span><br>' +
'<span class="js-file-size"></span> (Byte)<br>' +
'<img class="img-thumbnail js-file-image" style="width: 100%; height: 100%">' +
'</div>';
$('.js-file-list').append(str);
var imageSrc = event.target.result;
var fileName = file.name;
var fileSize = file.size;
$('.js-file-name').text(fileName);
$('.js-file-size').text(fileSize);
$('.js-file-image').attr('src', imageSrc);
};
fileReader.readAsDataURL(file);
});
});
- Kết quả thu được
2. Upload multi file:
- Để upload multi file, ta thêm thuộc tính
multiple
vào file input. - Ta có file upload_multi_file.html như sau, không khác nhiều so với upload_single_file.html.
<!DOCTYPE html>
<html>
<head>
<title>UPLOAD MULTI FILE</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="scripts/upload_multi_file.js"></script>
</head>
<body>
<div class="container">
<h2>Upload multi file</h2>
<form>
<div class="form-group">
<label>Select multi image files</label>
<input type="file" class="form-control" id="fileInput" multiple>
</div>
</form>
</div>
<div class="container js-file-list">
</div>
</body>
</html>
- Ta tạo file upload_multi_file.js để xử lí vệc upload file
$(document).ready(function(){
$('#fileInput').on('change', function() {
var files = $(this)[0].files;
for(var i = 0; i < files.length; i++) {
var file = files[i];
var fileReader = new FileReader();
fileReader.onload = function() {
var str = '<div class="col-md-2">' +
'<span class="js-file-name"></span><br>' +
'<span class="js-file-size"></span> (Byte)<br>' +
'<img class="img-thumbnail js-file-image" style="width: 100%; height: 100%">' +
'</div>';
$('.js-file-list').append(str);
var imageSrc = event.target.result;
var fileName = file.name;
var fileSize = file.size;
$('.js-file-name').last().text(fileName);
$('.js-file-size').last().text(fileSize);
$('.js-file-image').last().attr('src', imageSrc);
};
fileReader.readAsDataURL(file);
}
});
});
-
Ta tạo vòng lặp và xử lý tương tự như việc upload 1 file đối với từng file trong vòng lặp.
-
Kết quả thu được
-
Ta thấy file hiển thị đúng hình ảnh nhưng thông tin file đang bị sai (chỉ hiển thị duy nhất thông tin của 1 file).
-
Ta thực hiện thêm
console.log()
để DEBUG.
$(document).ready(function(){
$('#fileInput').on('change', function() {
var files = $(this)[0].files;
for(var i = 0; i < files.length; i++) {
var file = files[i];
console.log('DEBUG FOR');
console.log(i, file.name, file.size);
var fileReader = new FileReader();
fileReader.onload = function() {
console.log('DEBUG ONLOAD');
console.log(file.name, file.size);
var str = '<div class="col-md-2">' +
'<span class="js-file-name"></span><br>' +
'<span class="js-file-size"></span> (Byte)<br>' +
'<img class="img-thumbnail js-file-image" style="width: 100%; height: 100%">' +
'</div>';
$('.js-file-list').append(str);
var imageSrc = event.target.result;
var fileName = file.name;
var fileSize = file.size;
$('.js-file-name').last().text(fileName);
$('.js-file-size').last().text(fileSize);
$('.js-file-image').last().attr('src', imageSrc);
};
fileReader.readAsDataURL(file);
}
});
});
- Kết quả thu được:
- Ta thấy hàm
onload()
chạy sau khi vòng lặp for kết thúc do đó biến file nhận được trong hàmonload()
là file cuối cùng được upload. - Để giải quyết vấn đề này, ta thực hiện truyền biến file vào trong hàm
onload()
- Cú pháp truyền biến file vào hàm
onload()
như sau:
reader.onload = (function(fileParams) {
return function() {
// use fileParams here ...
};
})(fileParam);
- Ta update nội dung file upload_multi_file.js như sau:
$(document).ready(function(){
$('#fileInput').on('change', function() {
var files = $(this)[0].files;
for(var i = 0; i < files.length; i++) {
var file = files[i];
var fileReader = new FileReader();
fileReader.onload = (function(fileParams) {
return function(event) {
var str = '<div class="col-md-2">' +
'<span class="js-file-name"></span><br>' +
'<span class="js-file-size"></span> (Byte)<br>' +
'<img class="img-thumbnail js-file-image" style="width: 100%; height: 100%">' +
'</div>';
$('.js-file-list').append(str);
var imageSrc = event.target.result;
var fileName = fileParams.name;
var fileSize = fileParams.size;
$('.js-file-name').last().text(fileName);
$('.js-file-size').last().text(fileSize);
$('.js-file-image').last().attr('src', imageSrc);
};
})(file);
fileReader.readAsDataURL(file);
}
});
});
- Kết quả thu được:
- Ta thấy thông tin file đã hiển thị đúng thông tin nhưng không đúng theo thứ tự upload file, vấn đề này sẽ được giải quyết trong ví dụ tiếp theo.
3. Upload multi file with correct order:
- Trong ví dụ trên, ta thực hiện việc upload và show file trong vòng lặp, các
FileReader
object được tạo tuần tự nhưng hàmonload()
chỉ chạy khi việc upload file hoàn thành. - Do đó các hàm
onload()
không được chạy tuần tự như việc tạoFileReader
object và gây ra việc các file không được upload đúng theo thứ tự mong muốn. - Để giải quyết vấn đề này, ta cần đảm bảo các hàm
onload()
được chạy tuần tự đúng theo thứ tự upload file. - Trong ví dụ này, mình sử dụng phương pháp đệ quy, sau khi
FileRaeder
object được tạo hàmonload()
của 1 file chạy xong thì tiếp tục tạoFileReader
object và hàmonload()
cho file tiếp theo, với cách làm này, ta không cần thực hiện truyền biến file vào hàmonload()
. - Tạo function đệ quy
uploadFile(files, index)
như sau
function uploadFile(files, index) {
var length = files.length
if (index == length) {
return;
}
var file = files[index];
var fileReader = new FileReader();
fileReader.onload = function() {
var str = '<div class="col-md-2">' +
'<span class="js-file-name"></span><br>' +
'<span class="js-file-size"></span> (Byte)<br>' +
'<img class="img-thumbnail js-file-image" style="width: 100%; height: 100%">' +
'</div>';
$('.js-file-list').append(str);
var imageSrc = event.target.result;
var fileName = file.name;
var fileSize = file.size;
$('.js-file-name').last().text(fileName);
$('.js-file-size').last().text(fileSize);
$('.js-file-image').last().attr('src', imageSrc);
uploadFile(files, index + 1)
};
fileReader.readAsDataURL(file);
}
- Thực hiện gọi hàm uploadFile()
$('#fileInput').on('change', function() {
var files = $(this)[0].files;
uploadFile(files, 0)
});
- Kết quả thu được:
4. Source code tham khảo:
All rights reserved