Click here to Skip to main content
15,885,087 members
Articles / Web Development / HTML5

Lightweight Multiple File Upload with Thumbnail Preview using HTML5 and Client Side Scripts

Rate me:
Please Sign up or sign in to vote.
4.93/5 (16 votes)
11 Oct 2017CPOL3 min read 61.1K   4.8K   25   29
This article describes how to add a fully client side Multiple File Upload functionality to your page. Include select multiple files at a time, Select from different folders, Apply validation, show files in thumbnails and remove files from the list.

Image 1

Introduction

Uploading files as attachments is a common scenario and an essential part of many web applications.
I was in a situation where I needed a multiple file upload functionality on an HTML page that needed to be submitted one time to the server.

The beauty of this solution that it works completely from the client side. You can select multiple files at a time, select from different folders, apply validation, view the selected files in thumbnails preview and allow you to remove files from list. Therefore, it is very lightweight, because all of the overhead will remain on the client side.

Solution Summary

  1. Selecting multiple files at a time
  2. Selecting from different folders
  3. Apply validation on files extension, file size and number of uploaded files
  4. Listing the selected files in thumbnails preview
  5. Filtering the selected files by Allowing Remove file option
  6. Save the selected and filtered list of files in JavaScript array to be submitted to server

Background

You need to have a basic understanding of HTML5, CSS and client side script (JavaScript and JQuery).

Using the Code

Technical Introduction

HTML5 provides a standard way to deal with local files via via File API. File API can be used to create thumbnail preview of images, also you can use client-side logic to validate the uploaded files type, size and files count.

Selecting Files

I have used the standard HTML5 control for multiple file upload. This is the most straightforward way to upload a files element.

HTML
<input id="files" multiple="multiple" name="files[]" type="file" />    

To give the file upload control a modern look, I add a stylesheet for the file upload parent span.

HTML
<span class="btn btn-success fileinput-button">
    <span>Select Attachment</span>
        <input accept="image/jpeg, image/png, image/gif," 
         id="files" multiple="multiple" name="files[]" type="file" />
</span>

Image 2

After user selection; JavaScript returns the list of selected File objects as a FileList. I added an event handler for the file upload control to access the FileList properties.

JavaScript
document.addEventListener("DOMContentLoaded", init, false);
    
function init() {
    document.querySelector('#files').addEventListener('change', handleFileSelect, false);
}

Then, the event handler function:

JavaScript
function handleFileSelect(e) {
    //to make sure the user select file/files
    if (!e.target.files) return;

    //To obtain a File reference
    var files = e.target.files;

    // Loop through the FileList and then to render image files as thumbnails.
    for (var i = 0, f; f = files[i]; i++) 
    {
        //instantiate a FileReader object to read its contents into memory
        var fileReader = new FileReader();

        // Closure to capture the file information and apply validation.
        fileReader.onload = (function (readerEvt) {
            return function (e) {
                
                //Apply the validation rules for attachments upload
                ApplyFileValidationRules(readerEvt)

                //Render attachments thumbnails.
                RenderThumbnail(e, readerEvt);

                //Fill the array of attachment
                FillAttachmentArray(e, readerEvt)
            };
        })(f);

        // Read in the image file as a data URL.
        // readAsDataURL: The result property will contain the file/blob's data encoded as a data URL.
        // More info about Data URI scheme https://en.wikipedia.org/wiki/Data_URI_scheme
        fileReader.readAsDataURL(f);
    }
    document.getElementById('files').addEventListener('change', handleFileSelect, false);
}

Thumbnail Preview of Images

Image 3

After user's selection, we calls fileReader.readAsDataURL() on the file, and render a thumbnail by setting the 'src' attribute to a data URL.

JavaScript
//Render attachments thumbnails.
function RenderThumbnail(e, readerEvt)
{
    var li = document.createElement('li');
    ul.appendChild(li);
    li.innerHTML = ['<div class="img-wrap"> <span class="close">×</span>
                   <img class="thumb" src="', e.target.result, '" title="', escape(readerEvt.name), 
                    '" data-id="',readerEvt.name, '"/></div>'].join('');
 
    var div = document.createElement('div');
    div.className = "FileNameCaptionStyle";
    li.appendChild(div);
    div.innerHTML = [readerEvt.name].join('');
    document.getElementById('Filelist').insertBefore(ul, null);
}

Remove Files

Image 4

I have added the ability to remove files by adding <span class="close">×</span> (&-times; means x in HTML code) to each image preview. So when a user clicks on the red (x), it will be removed by calling the below Jquery function:

JavaScript
//To remove attachment once user click on x button
jQuery(function ($) {
    $('div').on('click', '.img-wrap .close', function () {
        var id = $(this).closest('.img-wrap').find('img').data('id');
 
        //to remove the deleted item from array
        var elementPos = AttachmentArray.map(function (x) { return x.FileName; }).indexOf(id);
        if (elementPos !== -1) {
            AttachmentArray.splice(elementPos, 1);
        }
 
        //to remove image tag
        $(this).parent().find('img').not().remove();
 
        //to remove div tag
        $(this).parent().find('div').not().remove();
 
        //to remove div tag
        $(this).parent().parent().find('div').not().remove();
 
        //to remove li tag
        var lis = document.querySelectorAll('#imgList li');
        for (var i = 0; li = lis[i]; i++) {
            if (li.innerHTML == "") {
                li.parentNode.removeChild(li);
            }
        }
 
    });
}
)

Validations

Image 5

I have applied three validation rules on the uploaded files as below:

1. File Types

The allowed file types are: (jpg/png/gif):

JavaScript
//To check file type according to upload conditions
function CheckFileType(fileType) {
    if (fileType == "image/jpeg") {
        return true;
    }
    else if (fileType == "image/png") {
        return true;
    }
    else if (fileType == "image/gif") {
        return true;
    }
    else {
        return false;
    }
    return true;
}

2. File Size

Uploaded file size should not exceed 300 KB for each:

JavaScript
//To check file Size according to upload conditions
function CheckFileSize(fileSize) {
    if (fileSize < 300000) {
        return true;
    }
    else {
        return false;
    }
    return true;
}

3. Files Count

The number of uploaded files count should not exceed 10.

JavaScript
//To check files count according to upload conditions
function CheckFilesCount(AttachmentArray) {
    //Since AttachmentArray.length return the next available index in the array,
    //I have used the loop to get the real length
    var len = 0;
    for (var i = 0; i < AttachmentArray.length; i++) {
        if (AttachmentArray[i] !== undefined) {
            len++;
        }
    }
    //To check the length does not exceed 10 files maximum
    if (len > 9) {
        return false;
    }
    else
    {
        return true;
    }
}

Then, showing the error message according to validation rules:

JavaScript
//Apply the validation rules for attachments upload
function ApplyFileValidationRules(readerEvt)
{
    //To check file type according to upload conditions
    if (CheckFileType(readerEvt.type) == false) 
    {
        alert("The file (" + readerEvt.name + ") does not match the upload conditions, 
                             You can only upload jpg/png/gif files");
            e.preventDefault();
            return;
    }

    //To check file Size according to upload conditions
    if (CheckFileSize(readerEvt.size) == false) 
    {
        alert("The file (" + readerEvt.name + ") does not match the upload conditions, 
               The maximum file size for uploads should not exceed 300 KB");
        e.preventDefault();
        return;
    }

    //To check files count according to upload conditions
    if (CheckFilesCount(AttachmentArray) == false) 
    {
        if (!filesCounterAlertStatus) 
        {
            filesCounterAlertStatus = true;
            alert("You have added more than 10 files. According to upload conditions, 
                   you can upload 10 files maximum");
        }
        e.preventDefault();
        return;
    }
}

Points of Interest

The final output from the client side will be a JavaScript array. You can send it to server side according to your solution architecture. For example, you can send it with JSON object, or save it in an HTML hidden field and read it from there.

For the upload rules like (number of files, file size and file type), I recommend keeping it in config file and read it from there.

If you are dealing with big size attachment, then you can add a progress bar that is supported by HTML5 also. It allows you to monitor the progress of a file read; useful for large files, catching errors, and figuring out when a read is complete. Read this for more information.

Browser Compatibility

This control has been tested on the latest version of Firefox, Internet Explorer, Chrome and Safari
"For old browsers version, you can check that browser fully supports the File API as below:"

JavaScript
// Check for the various File API support.
if (window.File && window.FileReader && window.FileList && window.Blob) 
{
    // Great success! All the File APIs are supported.
} 
else 
{
  alert('The File APIs are not fully supported in this browser.');
}
//source: https://www.html5rocks.com/en/tutorials/file/dndfiles/

Finally

I tried my best to make the code easy and clear. For further improvement; any comments, ideas, and suggestions are most welcome. Please provide a "Vote" if this would be helpful.

References

History

  • Version 1.0: 12/10/2017

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Saudi Arabia Saudi Arabia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questioncouple of minor issues with the validation Pin
Member 1547572630-Dec-21 16:02
Member 1547572630-Dec-21 16:02 
GeneralOnce an image deleted same image not selected again Pin
Member 1471371816-Jan-20 0:00
Member 1471371816-Jan-20 0:00 
Questionresize image before upload Pin
AminMhmdi5-Oct-19 21:29
professionalAminMhmdi5-Oct-19 21:29 
Questionimage orientation Pin
Member 1417314912-Mar-19 4:21
Member 1417314912-Mar-19 4:21 
AnswerRe: image orientation Pin
Yahya Mohammed Ammouri13-Jun-23 20:36
Yahya Mohammed Ammouri13-Jun-23 20:36 
QuestionAmazing job, it's just what I was looking for !! Pin
Member 1402729121-Oct-18 8:52
Member 1402729121-Oct-18 8:52 
QuestionUsing in PHP refreshing array data and filling hiddn input Pin
Member 1248939515-Oct-18 8:41
Member 1248939515-Oct-18 8:41 
QuestionHow to delete? Pin
Member 1399381522-Sep-18 1:08
Member 1399381522-Sep-18 1:08 
AnswerRe: How to delete? Pin
Yahya Mohammed Ammouri24-Sep-18 20:52
Yahya Mohammed Ammouri24-Sep-18 20:52 
QuestionClick more than once to select images. Pin
Member 1395337716-Sep-18 8:49
Member 1395337716-Sep-18 8:49 
AnswerRe: Click more than once to select images. Pin
Yahya Mohammed Ammouri24-Sep-18 20:58
Yahya Mohammed Ammouri24-Sep-18 20:58 
QuestionGet the file path from the array ... Pin
Member 1394936215-Aug-18 8:02
Member 1394936215-Aug-18 8:02 
AnswerRe: Get the file path from the array ... Pin
MT_8-Nov-18 3:05
professionalMT_8-Nov-18 3:05 
QuestionIn Request it is not updating when i delete the image by pressing the X button Pin
Member 138088539-Jun-18 9:17
Member 138088539-Jun-18 9:17 
AnswerRe: In Request it is not updating when i delete the image by pressing the X button Pin
Yahya Mohammed Ammouri4-Jul-18 19:45
Yahya Mohammed Ammouri4-Jul-18 19:45 
QuestionIf i select one by one scenario Pin
Member 138088537-Jun-18 18:46
Member 138088537-Jun-18 18:46 
AnswerRe: If i select one by one scenario Pin
Yahya Mohammed Ammouri4-Jul-18 19:57
Yahya Mohammed Ammouri4-Jul-18 19:57 
GeneralRe: If i select one by one scenario Pin
MT_8-Nov-18 3:04
professionalMT_8-Nov-18 3:04 
QuestionCode adaptation Pin
Member 1372850416-Mar-18 8:39
Member 1372850416-Mar-18 8:39 
AnswerRe: Code adaptation Pin
Yahya Mohammed Ammouri10-Apr-18 1:59
Yahya Mohammed Ammouri10-Apr-18 1:59 
QuestionLightweight Multiple File Upload with Thumbnail Preview using HTML5 and Client Side Scripts Pin
Member 1372850415-Mar-18 22:41
Member 1372850415-Mar-18 22:41 
SuggestionServer side image storage with ASP.NET MVC 5 / Entity Framework Pin
Rockdeveloper1618-Oct-17 23:35
Rockdeveloper1618-Oct-17 23:35 
GeneralRe: Server side image storage with ASP.NET MVC 5 / Entity Framework Pin
Yahya Mohammed Ammouri19-Oct-17 0:00
Yahya Mohammed Ammouri19-Oct-17 0:00 
QuestionCan you please change the sample images... Pin
haiduong8715-Oct-17 7:06
haiduong8715-Oct-17 7:06 
AnswerRe: Can you please change the sample images... Pin
Yahya Mohammed Ammouri15-Oct-17 19:17
Yahya Mohammed Ammouri15-Oct-17 19:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.