Mingle Li
Mingle Li

Reputation: 1350

HTML + JS - File name resets in text when adding a new file button

I have a add button, like this, to add more <input type="file">: enter image description here

And it does work, when I click on the button, it calls a method to add a new file chooser.

HTML:

<div class="row" id="attachments_row">
          <div class="coffee-span-4">
            <label class="label label-1">Attachments</label>
          </div>
          <div class="coffee-span-6" id="attachments">
            <div id="attachment_inner">
                <input id="file_button" type="file" name="fileUpload0" size="50" /> 
                <sf:errors path="filepath" cssClass="rfqerror"></sf:errors>
            </div>
            <input type="button" value="+" style="float: left; margin-top: 10px; margin-bottom: 10px; padding: 5px;" onclick="makeNewAttachment();"/>
          </div>

          <div class="coffee-span-2" id="file-upload-button">
          </div>

          <br>
</div>

JS:

function makeNewAttachment() {
    var ai = document.getElementById("attachment_inner").innerHTML;
    var index = document.getElementById("attachment_inner").children.length;
    var ai_new = ai + "<input id='file_button' type='file' name='fileUpload" + index + "' size='50' />";
    document.getElementById("attachment_inner").innerHTML = ai_new;
}

But when I choose a file, the file name resets back to No file chosen.

Chose a file:

enter image description here

Click add, resets?!?!?!?

enter image description here

Does anyone know why?! I made each name different, I thought that was the case, but nope!

Upvotes: 2

Views: 211

Answers (1)

Michael Laszlo
Michael Laszlo

Reputation: 12239

The problem is that you're duplicating the HTML text inside the div #attachment_inner, not the document objects that are the children of the div object. The text that represents the file-chooser input doesn't have an attribute representing the most recently chosen file name. That information is in the input object. Although the object was built from HTML text, that text isn't rewritten to reflect new information such as the name of the chosen file.

The solution is to use cloneNode() to make a deep copy of the object that you want to duplicate.

In the snippet below, I'm cloning the div containing the file chooser so that you also have a copy of the sf:errors tag and whatever else you might want to have along with the button. In addition, the container div makes layout easier. To avoid having multiple divs with the same id, I changed id="attachment_inner" to class="attachment_inner".

function makeNewAttachment() {
    var attachments = document.getElementById('attachments'),
        choosers = attachments.getElementsByClassName('attachment_inner'),
        numChoosers = choosers.length,
        newChooser = choosers[numChoosers - 1].cloneNode(true),
        input = newChooser.getElementsByTagName('input')[0];
    attachments.insertBefore(newChooser, document.getElementById('plusButton'));
    input.name = input.name.replace(/\d+$/, '' + numChoosers);
}
<div class="row" id="attachments_row">
          <div class="coffee-span-4">
            <label class="label label-1">Attachments</label>
          </div>
          <div class="coffee-span-6" id="attachments">
            <div class="attachment_inner">
                <input type="file" name="fileUpload0" size="50" /> 
                <sf:errors path="filepath" cssClass="rfqerror"></sf:errors>
            </div>
            <input id="plusButton" type="button" value="+" style="float: left; margin-top: 10px; margin-bottom: 10px; padding: 5px;" onclick="makeNewAttachment();"/>
          </div>

          <div class="coffee-span-2" id="file-upload-button">
          </div>

          <br>
</div>

Upvotes: 1

Related Questions