Clearing <input type='file' /> using jQuery
Asked Answered
E

27

559

Is it possible to clear an <input type='file' /> control value with jQuery? I've tried the following:

$('#control').attr({ value: '' }); 

But it's not working.

Expansile answered 25/6, 2009 at 13:32 Comment(0)
Z
532

Easy: you wrap a <form> around the element, call reset on the form, then remove the form using .unwrap(). Unlike the .clone() solutions otherwise in this thread, you end up with the same element at the end (including custom properties that were set on it).

Tested and working in Opera, Firefox, Safari, Chrome and IE6+. Also works on other types of form elements, with the exception of type="hidden".

window.reset = function(e) {
  e.wrap('<form>').closest('form').get(0).reset();
  e.unwrap();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<form>
  <input id="file" type="file">
  <br>
  <input id="text" type="text" value="Original">
</form>

<button onclick="reset($('#file'))">Reset file</button>
<button onclick="reset($('#text'))">Reset text</button>

JSFiddle

As Timo notes below, if you have the buttons to trigger the reset of the field inside of the <form>, you must call .preventDefault() on the event to prevent the <button> from triggering a submit.


EDIT

Does not work in IE 11 due to an unfixed bug. The text (file name) is cleared on the input, but its File list remains populated.

Zonked answered 12/11, 2012 at 20:40 Comment(10)
Winner! Works in every browser and avoids cloning input field. But if clear-buttons are inside form, please rename reset() to eg. reset2(), because at least in Chrome all fields are cleared if it is reset(). And add event.preventDefault() after clearing call to prevent submitting. This way: <button onclick="reset2($('#file'));event.preventDefault()">Reset file</button>. Working example: jsfiddle.net/rPaZQ/23.Zobkiw
@Timo, I've renamed the function to resetFormElement and added a note that you should preventDefault() on the button onclick.Zonked
Problem is, this at least temporarily makes the document invalid. (Forms can not contain other forms.) Whether it currently works or not, it's free to break any time it wants.Lots
@cHao, of course this is only true if the input element is actually in a form, which it does not have to be.Kelseykelsi
Latest Chrome doesn't like it (get(0) is undefined), I had to do .wrap('<form></form>'), as advised in jQuery doc anyway.Hatchment
Isn't that easier to call return false instead of ugly e.stopPropagation() and e.preventDefault() pair? It does exactly the same thing: api.jquery.com/on/#event-handlerEhrsam
This is failing for me in IE11 and Edge 20. It looks like its causing jquery.validator to bomb due to the brief period nested forms exist.Kwangju
@RobinLuiten You may want to try moving the input element up to document.body, wrapping in a <form>, resetting that form, then moving the element back to where it came from.Zonked
@Zonked ive gone back to $input.val('') which gave me problems 3 months back when I went to this solution. AT moment the simple solution seems to be working chrome/firefox/edge/ie11/ios safari/android chrome. Your suggestion is a good one and not one I had thought of thanks.Kwangju
Due to this function was called with jquery selector. Example reset($('#targetInput'));. So, to make IE 11 works just add e.val(''); after the e.unwrap(); line.Dreiser
S
434

Quick answer: replace it.

In the code below I use the replaceWith jQuery method to replace the control with a clone of itself. In the event you have any handlers bound to events on this control, we'll want to preserve those as well. To do this we pass in true as the first parameter of the clone method.

<input type="file" id="control"/>
<button id="clear">Clear</button>
var control = $("#control");

$("#clear").on("click", function () {
    control.replaceWith( control = control.clone( true ) );
});

Fiddle: http://jsfiddle.net/jonathansampson/dAQVM/

If cloning, while preserving event handlers, presents any issues you could consider using event delegation to handle clicks on this control from a parent element:

$("form").on("focus", "#control", doStuff);

This prevents the need for any handlers to be cloned along with the element when the control is being refreshed.

Stickleback answered 25/6, 2009 at 13:32 Comment(3)
The annoying thing with this solution is that you have to have the element twice in your code, so if someone changes, for example, the name, you have to change your code twice (which is very easy to forget)Convenient
You can also use the .clone() method on the field $('#clone').replaceWith($(this).clone());Lafond
It still doesn't work. It needs to be cleared prior to replacement. So you'd want .val() before .replaceWith(). So it'd be control.val('').replaceWith(...);Ist
R
113

Jquery is supposed to take care of the cross-browser/older browser issues for you.

This works on modern browsers that I tested: Chromium v25, Firefox v20, Opera v12.14

Using jquery 1.9.1

HTML

<input id="fileopen" type="file" value="" />
<button id="clear">Clear</button>

Jquery

$("#clear").click(function () {
    $("#fileopen").val("");
});

On jsfiddle

The following javascript solution also worked for me on the browsers mention above.

document.getElementById("clear").addEventListener("click", function () {
    document.getElementById("fileopen").value = "";
}, false);

On jsfiddle

I have no way to test with IE, but theoretically this should work. If IE is different enough that the Javascript version does not work because MS have done it in a different way, the jquery method should in my opinion deal with it for you, else it would be worth pointing it out to the jquery team along with the method that IE requires. (I see people saying "this won't work on IE", but no vanilla javascript to show how it does work on IE (supposedly a "security feature"?), perhaps report it as a bug to MS too (if they would count it as such), so that it gets fixed in any newer release)

Like mentioned in another answer, a post on the jquery forum

 if ($.browser.msie) {
      $('#file').replaceWith($('#file').clone());
 } else {
      $('#file').val('');
 }

But jquery have now removed support for browser testing, jquery.browser.

This javascript solution also worked for me, it is the vanilla equivalent of the jquery.replaceWith method.

document.getElementById("clear").addEventListener("click", function () {
    var fileopen = document.getElementById("fileopen"),
        clone = fileopen.cloneNode(true);

    fileopen.parentNode.replaceChild(clone, fileopen);
}, false);

On jsfiddle

The important thing to note is that the cloneNode method does not preserve associated event handlers.

See this example.

document.getElementById("fileopen").addEventListener("change", function () {
    alert("change");
}, false);

document.getElementById("clear").addEventListener("click", function () {
    var fileopen = document.getElementById("fileopen"),
        clone = fileopen.cloneNode(true);

    fileopen.parentNode.replaceChild(clone, fileopen);
}, false);

On jsfiddle

But jquery.clone offers this [*1]

$("#fileopen").change(function () {
    alert("change");
});

$("#clear").click(function () {
    var fileopen = $("#fileopen"),
        clone = fileopen.clone(true);

    fileopen.replaceWith(clone);
});

On jsfiddle

[*1] jquery is able to do this if the events were added by jquery's methods as it keeps a copy in jquery.data, it does not work otherwise, so it's a bit of a cheat/work-around and means things are not compatible between different methods or libraries.

document.getElementById("fileopen").addEventListener("change", function () {
    alert("change");
}, false);

$("#clear").click(function () {
    var fileopen = $("#fileopen"),
        clone = fileopen.clone(true);

    fileopen.replaceWith(clone);
});

On jsfiddle

You can not get the attached event handler direct from the element itself.

Here is the general principle in vanilla javascript, this is how jquery an all other libraries do it (roughly).

(function () {
    var listeners = [];

    function getListeners(node) {
        var length = listeners.length,
            i = 0,
            result = [],
            listener;

        while (i < length) {
            listener = listeners[i];
            if (listener.node === node) {
                result.push(listener);
            }

            i += 1;
        }

        return result;
    }

    function addEventListener(node, type, handler) {
        listeners.push({
            "node": node,
                "type": type,
                "handler": handler
        });

        node.addEventListener(type, handler, false);
    }

    function cloneNode(node, deep, withEvents) {
        var clone = node.cloneNode(deep),
            attached,
            length,
            evt,
            i = 0;

        if (withEvents) {
            attached = getListeners(node);
            if (attached) {
                length = attached.length;
                while (i < length) {
                    evt = attached[i];
                    addEventListener(clone, evt.type, evt.handler);

                    i += 1;
                }
            }
        }

        return clone;
    }

    addEventListener(document.getElementById("fileopen"), "change", function () {
        alert("change");
    });

    addEventListener(document.getElementById("clear"), "click", function () {
        var fileopen = document.getElementById("fileopen"),
            clone = cloneNode(fileopen, true, true);

        fileopen.parentNode.replaceChild(clone, fileopen);
    });
}());

On jsfiddle

Of course jquery and other libraries have all the other support methods required for maintaining such a list, this is just a demonstration.

Rounce answered 16/5, 2013 at 19:40 Comment(0)
T
51

For obvious security reasons you can't set the value of a file input, even to an empty string.

All you have to do is reset the form where the field or if you only want to reset the file input of a form containing other fields, use this:

function reset_field (e) {
    e.wrap('<form>').parent('form').trigger('reset');
    e.unwrap();
}​

Here is an exemple: http://jsfiddle.net/v2SZJ/1/

Tullus answered 19/6, 2013 at 4:42 Comment(0)
C
43

This works for me.

$("#file").replaceWith($("#file").clone());

http://forum.jquery.com/topic/how-to-clear-a-file-input-in-ie

Hope it helps.

Corned answered 29/4, 2013 at 8:31 Comment(1)
Works for me! It's worth noting that if you have any event listeners triggered by a change in the file input then you need to reassign them once you have replaced the input.Nakisha
S
20

In IE8 they made the File Upload field read-only for security. See the IE team blog post:

Historically, the HTML File Upload Control () has been the source of a significant number of information disclosure vulnerabilities. To resolve these issues, two changes were made to the behavior of the control.

To block attacks that rely on “stealing” keystrokes to surreptitiously trick the user into typing a local file path into the control, the File Path edit box is now read-only. The user must explicitly select a file for upload using the File Browse dialog.

Additionally, the “Include local directory path when uploading files” URLAction has been set to "Disable" for the Internet Zone. This change prevents leakage of potentially sensitive local file-system information to the Internet. For instance, rather than submitting the full path C:\users\ericlaw\documents\secret\image.png, Internet Explorer 8 will now submit only the filename image.png.

Starknaked answered 27/7, 2009 at 15:29 Comment(0)
D
18

$("#control").val('') is all you need! Tested on Chrome using JQuery 1.11

Other users have tested in Firefox as well.

Drida answered 20/9, 2015 at 16:53 Comment(4)
As many other posts on here explain, this isn't cross browser friendly.Squama
For my understanding which browsers does this fail in?Cheapen
Fails in Internet Explorer as input type file is readonly in IE>Polymerism
Works in chrome and firefox. More than enough.Levirate
R
13

I got stuck with all the options here. Here's a hack that I made which worked:

<form>
 <input type="file">
 <button type="reset" id="file_reset" style="display:none">
</form>

and you can trigger the reset using jQuery with a code similar to this:

$('#file_reset').trigger('click');

(jsfiddle: http://jsfiddle.net/eCbd6/)

Ramakrishna answered 22/1, 2014 at 18:16 Comment(1)
ok but it will clear the entire form.. not specific file inputHebraic
S
8

I ended up with this:

if($.browser.msie || $.browser.webkit){
  // doesn't work with opera and FF
  $(this).after($(this).clone(true)).remove();  
}else{
  this.setAttribute('type', 'text');
  this.setAttribute('type', 'file'); 
}

may not be the most elegant solution, but it work as far as I can tell.

Sur answered 14/8, 2012 at 13:36 Comment(3)
#8379063Gillan
doesn't work in chrome 34 (linux). replaceWith() method works in both browsers (chrome, firefox)Prakrit
At the first I must notice "The $.browser has been removed from jquery 1.9" but the last two lines (Changing type attribute to text and then set back it to the file) worked. Additionally I tried to set $('#control').val(''); or in javascript document.getElementById(control).value = ''; and worked too and don't know why we shouldn't using this approach!? Finally, I decided to use both of them.Scenario
G
8

I have used https://github.com/malsup/form/blob/master/jquery.form.js, which has a function called clearInputs(), which is crossbrowser, well tested, easy to use and handles also IE issue and hidden fields clearing if needed. Maybe a little long solution to only clear file input, but if you are dealing with crossbrowser file uploads, then this solution is recommended.

The usage is easy:

// Clear all file fields:
$("input:file").clearInputs();

// Clear also hidden fields:
$("input:file").clearInputs(true);

// Clear specific fields:
$("#myfilefield1,#myfilefield2").clearInputs();
/**
 * Clears the selected form elements.
 */
$.fn.clearFields = $.fn.clearInputs = function(includeHidden) {
    var re = /^(?:color|date|datetime|email|month|number|password|range|search|tel|text|time|url|week)$/i; // 'hidden' is not in this list
    return this.each(function() {
        var t = this.type, tag = this.tagName.toLowerCase();
        if (re.test(t) || tag == 'textarea') {
            this.value = '';
        }
        else if (t == 'checkbox' || t == 'radio') {
            this.checked = false;
        }
        else if (tag == 'select') {
            this.selectedIndex = -1;
        }
        else if (t == "file") {
            if (/MSIE/.test(navigator.userAgent)) {
                $(this).replaceWith($(this).clone(true));
            } else {
                $(this).val('');
            }
        }
        else if (includeHidden) {
            // includeHidden can be the value true, or it can be a selector string
            // indicating a special test; for example:
            //  $('#myForm').clearForm('.special:hidden')
            // the above would clean hidden inputs that have the class of 'special'
            if ( (includeHidden === true && /hidden/.test(t)) ||
                 (typeof includeHidden == 'string' && $(this).is(includeHidden)) )
                this.value = '';
        }
    });
};
Gusgusba answered 3/4, 2013 at 4:21 Comment(3)
I don't understand why this answer isn't more upvoted ?!Sweltering
@AlexB: Because, as Timo explained, it's overkill just to clear one file input field.Azide
Don't know if that worked but no more on FF 45.0.2:(Carousal
R
5

The value of file inputs is read only (for security reasons). You can't blank it programatically (other than by calling the reset() method of the form, which has a broader scope than just that field).

Rabelaisian answered 25/6, 2009 at 13:35 Comment(4)
I'm confused - I tried $("#inputControl").val("") and it did indeed blank the field. Am I missing something?China
@Jonathan, works for me too, but if you set it to anything else it's a security error. Tested in FF4.Unroll
reset() is a JS native method so if you select the form via jQuery you need to take the element out of jQuery scope. $("form#myForm")[0].reset();Avner
@Jonathan It works for you because you did not do it in IE. This security issue is something that only IE stops. Clearing the value regularly works in both Chrome and Firefox, but not IEJudy
B
5

I was able to get mine working with the following code:

var input = $("#control");    
input.replaceWith(input.val('').clone(true));
Bunny answered 11/6, 2014 at 1:2 Comment(0)
S
5

I have been looking for simple and clean way to clear HTML file input, the above answers are great, but none of them really answers what i'm looking for, until i came across on the web with simple an elegant way to do it :

var $input = $("#control");

$input.replaceWith($input.val('').clone(true));

all the credit go's to Chris Coyier.

// Referneces
var control = $("#control"),
    clearBn = $("#clear");

// Setup the clear functionality
clearBn.on("click", function(){
    control.replaceWith( control.val('').clone( true ) );
});

// Some bound handlers to preserve when cloning
control.on({
    change: function(){ console.log( "Changed" ) },
     focus: function(){ console.log(  "Focus"  ) }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<input type="file" id="control">
<br><br>
<a href="#" id="clear">Clear</a>
Salgado answered 13/12, 2017 at 14:24 Comment(0)
G
4

The .clone() thing does not work in Opera (and possibly others). It keeps the content.

The closest method here for me was Jonathan's earlier, however ensuring that the field preserved its name, classes, etc made for messy code in my case.

Something like this might work well (thanks to Quentin too):

function clearInput($source) {
    var $form = $('<form>')
    var $targ = $source.clone().appendTo($form)
    $form[0].reset()
    $source.replaceWith($targ)
}
Gook answered 24/8, 2012 at 2:57 Comment(2)
Has this been tested in all major browsers?Trentontrepan
It seems to work fine in the latest version of Chrome/FF/Opera, and in IE8. I can't see any reason why it wouldn't work on anything - the reset option on forms has been around a long time.Gook
B
4

I have managed to get this to work using the following...

function resetFileElement(ele) 
{
    ele.val(''); 
    ele.wrap('<form>').parent('form').trigger('reset');   
    ele.unwrap();
    ele.prop('files')[0] = null;
    ele.replaceWith(ele.clone());    
}

This has been tested in IE10, FF, Chrome & Opera.

There are two caveats...

  1. Still doesn't work properly in FF, if you refresh the page, the file element gets re-populated with the selected file. Where it is getting this info from is beyond me. What else related to a file input element could I possible try to clear?

  2. Remember to use delegation on any events you had attached to the file input element, so they still work when the clone is made.

What I don't understand is who on earth thought not allowing you to clear an input field from an invalid unacceptable file selection was a good idea?

OK, don't let me dynamically set it with a value so I can't leach files from a user's OS, but let me clear an invalid selection without resetting an entire form.

It's not like 'accept' does anything other than a filter anyhow and in IE10, it doesn't even understand MS Word mime types, it's a joke!

Bertie answered 24/6, 2014 at 12:10 Comment(1)
This almost works. The one thing you need to do to make this work in Firefox is to use .pop() on the array of files instead of setting it to null. this seems to clear out the file properly.Lebensraum
C
2

On my Firefox 40.0.3 only work with this

 $('input[type=file]').val('');
 $('input[type=file]').replaceWith($('input[type=file]').clone(true));
Craft answered 14/9, 2015 at 22:52 Comment(1)
$('input[type=file]').replaceWith($('input[type=file]').clone(true).val(''));Corabella
I
2

its works for me in every browser.

        var input = $(this);
        var next = this.nextSibling;
        var parent = input.parent();
        var form = $("<form></form>");
        form.append(input);
        form[0].reset();
        if (next) {
            $(next).before(input);
        } else {
            parent.append(input);
        }
Inexact answered 28/2, 2017 at 3:59 Comment(0)
A
1

I tried with the most of the techniques the users mentioned, but none of they worked in all browsers. i.e: clone() doesn't work in FF for file inputs. I ended up copying manually the file input, and then replacing the original with the copied one. It works in all browsers.

<input type="file" id="fileID" class="aClass" name="aName"/>

var $fileInput=$("#fileID");
var $fileCopy=$("<input type='file' class='"+$fileInput.attr("class")+" id='fileID' name='"+$fileInput.attr("name")+"'/>");
$fileInput.replaceWith($fileCopy);
Anuran answered 16/1, 2014 at 17:21 Comment(0)
V
0

$("input[type=file]").wrap("<div id='fileWrapper'/>");
$("#fileWrapper").append("<div id='duplicateFile'   style='display:none'>"+$("#fileWrapper").html()+"</div>");
$("#fileWrapper").html($("#duplicateFile").html());
Veto answered 8/9, 2011 at 8:35 Comment(1)
Hi Niraj. Welcome. This answer may well be correct but it could use some explanation.Mithgarthr
I
0

This works with Chrome, FF, and Safari

$("#control").val("")

May not work with IE or Opera

Instate answered 29/6, 2012 at 17:35 Comment(2)
Looks almost identical to the very problem in the OPMook
is not a ecmascript standard, the value of input type file is a protect property for security reasons.Headspring
S
0

Make it asynchronous, and reset it after the button's desired actions have been done.

    <!-- Html Markup --->
    <input id="btn" type="file" value="Button" onchange="function()" />

    <script>
    //Function
    function function(e) {

        //input your coding here           

        //Reset
        var controlInput = $("#btn");
        controlInput.replaceWith(controlInput = controlInput.val('').clone(true));
    } 
    </script>
Sherborne answered 19/4, 2013 at 17:55 Comment(0)
V
0
function clear() {
    var input = document.createElement("input");
    input.setAttribute('type', 'file');
    input.setAttribute('value', '');
    input.setAttribute('id', 'email_attach');

    $('#email_attach').replaceWith( input.cloneNode() );
}
Vastha answered 12/1, 2018 at 23:52 Comment(0)
T
0

it does not work for me:

$('#Attachment').replaceWith($(this).clone());
or 
$('#Attachment').replaceWith($('#Attachment').clone());

so in asp mvc I use razor features for replacing file input. at first create a variable for input string with Id and Name and then use it for showing in page and replacing on reset button click:

@{
    var attachmentInput = Html.TextBoxFor(c => c.Attachment, new { type = "file" });
}

@attachmentInput

<button type="button" onclick="$('#@(Html.IdFor(p => p.Attachment))').replaceWith('@(attachmentInput)');">--</button>
Trogon answered 27/12, 2018 at 11:57 Comment(0)
E
0

An easy way is changing the input type and change it back again.

Something like this:

var input = $('#attachments');
input.prop('type', 'text');
input.prop('type', 'file')
End answered 15/10, 2019 at 12:16 Comment(0)
M
-1

You can replace it with its clone like so

var clone = $('#control').clone();

$('#control').replacewith(clone);

But this clones with its value too so you had better like so

var emtyValue = $('#control').val('');
var clone = emptyValue.clone();

$('#control').replacewith(clone);
Mitzvah answered 19/12, 2017 at 5:54 Comment(0)
B
-4

It's easy lol (works in all browsers [except opera]):

$('input[type=file]').each(function(){
    $(this).after($(this).clone(true)).remove();
});

JS Fiddle: http://jsfiddle.net/cw84x/1/

Ballottement answered 11/8, 2012 at 15:56 Comment(2)
I coudn't care less about opera. Just wrap it in the form then if you care. I personally don't care and I will use my method.Ballottement
This isn't a good answer at all but the main problem was the really bad attitudeCaryloncaryn
F
-5

What? In your validation function, just put

document.onlyform.upload.value="";

Assuming upload is the name:

<input type="file" name="upload" id="csv_doc"/>

I'm using JSP, not sure if that makes a difference...

Works for me, and I think it's way easier.

Falcon answered 22/6, 2011 at 14:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.