1

Having a bit of trouble controlling my filelists when using multiple file type inputs. To be clear, I am not using a file input with multiple, but multiple single file inputs. The scenario is that a user can select 1 to 5 files, clear them all if they want, but still must send at least 1 file. So I have a max of five file inputs that I will be using on the form. For starters, I have two that I have put into a Fiddle and a CodePen (for some reason they are not working like they are on my local). The user selects a file, that file and size is added to a separate list which shows the name and size and has a button appended to that which calls the clearfileInput function. The clearFileInput function deletes that file input (since that seems to be the only way to truly remove the file so it does not get sent) and I need it to clear the list as well.

CODEPEN HERE JS FIDDLE HERE

Here is the HTML:

  <input type="file" name="filesToUpload" id="filesToUpload" onChange="makeFileList();" />
  <input type="file" name="filesToUpload" id="filesToUpload2" onChange="makeFileList2();" />

 <ul id="fileList"><li>No Files Selected</li></ul>
 <ul id="fileList2"><li>No Files Selected</li></ul>

And the script I am using is quite long because I have to duplicate everything but here is the complete script for one:

function makeFileList() {
    var input = document.getElementById("filesToUpload");
    var ul = document.getElementById("fileList");
    while (ul.hasChildNodes()) {
        ul.removeChild(ul.firstChild);
    }
    for (var i = 0; i < input.files.length; i++) {
        var li = document.createElement("li");
        var fileSize = input.files[i].size;
        li.innerHTML = input.files[i].name +"&nbsp;"+ "<span id=\"lblSize\"></span><input onclick=\"clearFileInput()\" type=\"button\" value=\"Clear\" \/>";
        ul.appendChild(li);
    }
    if(!ul.hasChildNodes()) {
        var li = document.createElement("li");
        li.innerHTML = 'No Files Selected';
        ul.appendChild(li);
    }
};
function makeFileList2() {
    var input = document.getElementById("filesToUpload2");
    var ul = document.getElementById("fileList2");
    while (ul.hasChildNodes()) {
        ul.removeChild(ul.firstChild);
    }
    for (var i = 0; i < input.files.length; i++) {
        var li = document.createElement("li");
        var fileSize = input.files[i].size;
        li.innerHTML = input.files[i].name +"&nbsp;"+"<span id=\"lblSize2\"></span><input onclick=\"clearFileInput2()\" type=\"button\" value=\"Clear\" \/>";
        ul.appendChild(li);
    }
    if(!ul.hasChildNodes()) {
        var li = document.createElement("li");
        li.innerHTML = 'No Files Selected';
        ul.appendChild(li);
    }
};
//Code Starts
$(document).ready(function() {
    $("#filesToUpload").change(function ()
    {
        var iSize = 0;
        if($.browser.msie)
        {
            var objFSO = new ActiveXObject("Scripting.FileSystemObject");
            var sPath = $("#filesToUpload")[0].value;
            var objFile = objFSO.getFile(sPath);
            var iSize = objFile.size;
            iSize = iSize/ 1024;
        }
        else
            iSize = ($("#filesToUpload")[0].files[0].size / 1024);

        if (iSize / 1024 > 1)
        {
            if (((iSize / 1024) / 1024) > 1)
            {
                iSize = (Math.round(((iSize / 1024) / 1024) * 100) / 100);
                $("#lblSize").html( iSize + "Gb");
            }
            else
            {
                iSize = (Math.round((iSize / 1024) * 100) / 100)
                $("#lblSize").html( iSize + "Mb");
            }
        }
        else
        {
            iSize = (Math.round(iSize * 100) / 100)
            $("#lblSize").html( iSize  + "kb");
        }
    });
    $("#filesToUpload2").change(function ()
    {
        var iSize2 = 0;
        if($.browser.msie)
        {
            var objFSO = new ActiveXObject("Scripting.FileSystemObject");
            var sPath = $("#filesToUpload2")[0].value;
            var objFile = objFSO.getFile(sPath);
            var iSize2 = objFile.size;
            iSize = iSize/ 1024;
        }
        else
            iSize2 = ($("#filesToUpload2")[0].files[0].size / 1024);

        if (iSize2 / 1024 > 1)
        {
            if (((iSize2 / 1024) / 1024) > 1)
            {
                iSize2 = (Math.round(((iSize2 / 1024) / 1024) * 100) / 100);
                $("#lblSize2").html( iSize2 + "Gb");
            }
            else
            {
                iSize2 = (Math.round((iSize2 / 1024) * 100) / 100)
                $("#lblSize2").html( iSize2 + "Mb");
            }
        }
        else
        {
            iSize2 = (Math.round(iSize2 * 100) / 100)
            $("#lblSize2").html( iSize2  + "kb");
        }
    });
});
function clearFileInput(){
    var oldInput = document.getElementById("filesToUpload");
    var newInput = document.createElement("input");
    newInput.type = "file";
    newInput.id = oldInput.id;
    newInput.name = oldInput.name;
    newInput.className = oldInput.className;
    newInput.style.cssText = oldInput.style.cssText;
    newInput.setAttribute("onclick", "makeFileList()");
    oldInput.parentNode.replaceChild(newInput, oldInput);
};
function clearFileInput2(){
    var oldInput = document.getElementById("filesToUpload2");
    var newInput = document.createElement("input");
    newInput.type = "file";
    newInput.id = oldInput.id;
    newInput.name = oldInput.name;
    newInput.className = oldInput.className;
    newInput.style.cssText = oldInput.style.cssText;
    newInput.setAttribute("onclick", "makeFileList2()");
    oldInput.parentNode.replaceChild(newInput, oldInput);
}
8
  • Just to make sure I am clear on your question... You already have 're-create the file input' working, but you just need it to clear out whatever li was input when you hit the 'clear file' button? Commented Oct 9, 2014 at 12:52
  • Yes that is correct. However, I am not able to find a way to add the onClick behavior when the input is rebuilt so I may have to change that to a jQuery empty().append solution. But for this question I am trying to just clear the filelist that corresponds to the file input being deleted. Commented Oct 9, 2014 at 12:55
  • Actually, found out what I was doing wrong in another post. So yes to answer your initial question, just clear that file list is what I am trying to do. Tried a jQuery empty() but it completely broke the list functionality. Commented Oct 9, 2014 at 13:20
  • Could I see how you tried the .empty()? I'm in the process of writing up an answer, and I want to make sure I don't replicate something you have already seen fail. Commented Oct 9, 2014 at 13:22
  • One minute, I see something I messed up. It is actually clearing it but only when it (the file input is changed or clicked) Reworking fiddle and pen now. Commented Oct 9, 2014 at 13:24

1 Answer 1

2

Okay, we'll tackle the easier issue first. Delete/recreate the file input. This is reffed from an archive question deeper into SO...

Instead of manually copying the input, use jquery's native clone capabilities, because it has an option to persist all event handlers as well. As below...

var upload1 = $('#fileUpload');
upload1.replaceWith( upload1 = upload1.clone( true ) );
//passing true to .clone persists all event handlers

As for the rest of this, you could probably simplify it down further by adding in some non-standard attributes to your html and targeting them instead of going by id (and having to replicate your JS 5 times.)

<input type="file" name="filesToUpload" id="filesToUpload" onChange="makeFileList();" />
<input type="file" name="filesToUpload" id="filesToUpload2" onChange="makeFileList2();" />

<ul class="fileList" fileUploadId="filesToUpload"><li>No Files Selected</li></ul>
<ul class="fileList" fileUploadId="filesToUpload2"><li>No Files Selected</li></ul>

And here we go with trimmed down JS

$(document).ready(function() {
    $('[name="filesToUpload"]').change(function() {
        var activeInput = $(this); //grabs the jq object of whatever is sending the click event
        //Do all your file handling here, I'm going to skip to the li tinkering.

        var ul = $('ul[fileUploadId="' + activeInput.attr('id') + '"]');
        ul.empty(); //performs the same action as your loop clearing out children
        //The rest of this is pretty straight forward to figure out, so I'll leave that
        //for you, and skip ahead to using the 'clear' button. just use the 'ul' var
        //and it will target the correct ul for what you are trying to do.

        //After you have added the button and actually attached it to the DOM, in this same function, we will give it its click listener. 
        //Give the button the 'clearFile' class
        $('.clearFile').off('click'); //remove the click listeners so we don't have them multiple times.
        $('.clearFile').click(function(){
            var buttonClicked = $(this);
            var parentUl = buttonClicked.closest('ul');
            //the following two lines replace that entire oldInput newInput process you were doing.
            var fileUpload = $('#' + parentUl.attr('fileUploadId'));
            fileUpload .replaceWith( fileUpload = fileUpload .clone( true ) );
            parentUl.empty();
    )};
)};

You could also create a single ul, and perform all your manipulations on the li level, by shuffling that 'fileUploadId' attribute down to the li instead...might make for tidier code.

I realize I have left some chunks out for the sake of getting this written with something resembling speed, so if you need clarifications, please ask.

Sign up to request clarification or add additional context in comments.

2 Comments

Ok, let me give that try. On my way into work so will be about an hour but yes... this has much deeper logic and control and I actually need to be able to hide/show track the file size and validate before sending but those will have to be other questions. Will work with this and be back in a bit. Thank you.
ok, yes please I need clarification on how to build the list within the jQuery function you have. What I am trying is not working.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.