locked
How Do I Remove a Specific File From an Input on Click? RRS feed

  • Question

  • User-939035612 posted

    I have a file input with a multiple attribute and would like to give users to ability to remove any single file by clicking a button. To do this I have a image preview feature that includes a button with each image. I would like to remove the corresponding image from the input when the remove button is clicked, but so far I can only find ways to remove all images from the input when that button is clicked. The end result is an image upload feature that requires every image to be removed one needs removing.

    I have searched the internet for a solution to this but found most solutions to state that because FileList is read only that you cannot use jQuery/javascript to remove just one file from the list. This leaves me wondering if there might be a way to remove all files and add just the remaining files after the remove button is clicked. 

    Here is my code so far:

    <div class="form-group">
                <div>
                    <div class="input-group mb-3 px-2 py-2 rounded-pill bg-white shadow-sm">
                        <input asp-for="FormFiles" id="upload2" type="file" multiple class="form-control border-0 upload" accept="@GlobalStatic.SITEIMGMIMETYPES()">
                        <label asp-for="FormFiles" id="upload-label2" for="upload2" class="font-weight-light text-muted upload-label">Images (Optional)</label>
                        <div class="input-group-append">
                            <label for="upload2" class="btn btn-light m-0 rounded-pill px-4"> <i class="fa fa-upload mr-2 text-muted"></i><small class="text-uppercase font-weight-bold text-muted">Choose Images</small></label>
                        </div>
                        <span id="error-FormFiles" class="text-danger" asp-validation-for="FormFiles"></span>
                    </div>
                    <div class="bg-light">
                        <p class="font-italic text-black-50 text-center">The image uploaded will be rendered inside the box below.</p>
                        <div id="imageResults" class="image-area mt-4"></div>
                    </div>
                </div>
            </div>
    <script>
    const form = document.getElementById('newpost');
    const input2 = document.getElementById('upload2');
    const infoArea2 = document.getElementById('upload-label2');
    $(input2).on('change', function () {
            readURL2(input2);
        });
    function readURL2(input2) {
        if (input2.files && input2.files.length > 0) {
            var ic1 = 0;
            var ic2 = 0;
            var ic3 = 0;
            var ic4 = 0;
            var ic5 = 0;
            var ic6 = 0;
            var ic7 = 0;
            for (var i = 0; i < input2.files.length; i++) {
                ++ic1;
                var files = event.target.files;
                let file = files[i];
                var reader2 = new FileReader();
                reader2.onload = function (e) {
                    $('#imageResults').append('<div id="imageWrapper_' + (++ic7) + '"><button type="button" class="close mb-2" aria-label="Close"><small aria-hidden="true">&times;REMOVE</small></button><img id="imageResult_' + (ic1) + '" src="' + e.target.result + '" alt="" class="img-fluid w-100 rounded shadow-sm mx-auto d-block"><div class="row mb-3 mt-3"><div class="col-sm-2"><label id="nameLabel_" for="imageName_' + (++ic2) + '">Name Above Image:</label></div><div class="col-sm-7"><input id="imageName_' + (++ic3) + '" name="imageName-' + (++ic4) + '" onchange="reValidateForm();" class="form-control" type="text"  data-val="true" data-val-maxlength="Max 50 Chars." data-val-maxlength-max="50" data-val-regex="No HTML tags allowed!" data-val-regex-pattern="^(?!.*&lt;[^&gt;]&#x2B;&gt;).*" maxlength="50" value="" /></div><span class="text-danger col-sm-3 col-form-label" data-valmsg-for="imageName-' + (++ic5) + '" data-valmsg-replace="true"></span></div></div>');
                };
                infoArea2.textContent = 'Image Count: ' + input2.files.length;
                reader2.readAsDataURL(input2.files[i]);
            }
        }
        reValidateForm();
        }
    $('#imageResults').on("click", ".close", function (e) { //user click on remove text
        e.preventDefault();
        $(input2).val('');
        $('#imageResults').empty();
        infoArea2.textContent = 'Image Count: ' + input2.files.length;
       reValidateForm();
    });
    </script>

    UPDATE: I just noticed another problem. When I add another image after already adding one the image is not added to the FileList. It replaces whatever is already in the FileList. It also orders the files alphabetically by name when I would prefer that they be added in the order selected.

    Tuesday, December 8, 2020 12:05 AM

All replies

  • User753101303 posted

    Hi,

    The problem is that this is a user input control that is exposing what the user entered and so you have little control on that (AFAIK you can just clear this list). Now you could copy this list to your own. Then a  trick might be to use drag and drop support as shown at https://stackoverflow.com/questions/8006715/drag-drop-files-into-standard-html-file-input to update this list.

    You could also have a look at Outlook and/or OneDrive. If I remember as soon as files are selected, they start to be uploaded (they likely copy as well to their own list) and you can cancel an upload. I believe that if the user is selecting new files they are added to the upload queue. But for now giving this a look for my own apps is still on my todo list.

    Tuesday, December 8, 2020 1:18 AM
  • User-939035612 posted

    So basically it is impossible to do this with a HTML input element? Some moron created it in such a way that you cannot delete files from the file list. What now? Do I have to add something that looks like an input using some other type of element, get an array from that, and save image array using some other method?

    Tuesday, December 8, 2020 4:37 AM
  • User-1151440187 posted

    Use this :

    $('#imageResults').on("click", ".close", function (e) { //user click on remove text
        e.preventDefault();
        $(input2).val('');
        e.currentTarget.parentNode.remove();
        infoArea2.textContent = 'Image Count: ' + input2.files.length;
       reValidateForm();
    });

    Hope it helps.

    Tuesday, December 8, 2020 5:06 AM
  • User-939035612 posted

    That change clears the FileList in the input but leaves preview images visible to the user. That is really confusing because it would make someone think the files are still part of the FileList.

    Tuesday, December 8, 2020 6:06 AM
  • User-1151440187 posted

    I don't understand your question exactly.

    can you explain using some pics. How do you want the output?

    Tuesday, December 8, 2020 1:19 PM
  • User475983607 posted

    So basically it is impossible to do this with a HTML input element? Some moron created it in such a way that you cannot delete files from the file list. What now? Do I have to add something that looks like an input using some other type of element, get an array from that, and save image array using some other method?

    Luckily, the morons openly documented the specifications.   Basically the user controls which files to upload when using the file input.

    The FromData API allows programmatic add/remove files before submitting the files.  The files must come from the file input element and you must use JavaScript to submit the files (AJAX/fetch).

    Consider looking into a file drag and drop API as recommended above.

    https://www.google.com/search?q=file+upload+drag+and+drop

    Tuesday, December 8, 2020 2:10 PM
  • User-474980206 posted

    another common solution is to just auto upload the file when selected (really common with drag and drop). then the list is maintained by the server. 

    Tuesday, December 8, 2020 4:06 PM