Clearing <input type='file' /> using jQuery

466,554

Solution 1

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.

Solution 2

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.

Solution 3

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.

Solution 4

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/

Solution 5

This works for me.

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

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

Hope it helps.

Share:
466,554
Admin
Author by

Admin

Updated on October 16, 2020

Comments

  • Admin
    Admin over 3 years

    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.

  • Sampson
    Sampson about 15 years
    I'm confused - I tried $("#inputControl").val("") and it did indeed blank the field. Am I missing something?
  • user14322501
    user14322501 about 13 years
    @Jonathan, works for me too, but if you set it to anything else it's a security error. Tested in FF4.
  • Chris Stephens
    Chris Stephens about 13 years
    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();
  • Casebash
    Casebash over 12 years
    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)
  • metric152
    metric152 over 12 years
    You can also use the .clone() method on the field $('#clone').replaceWith($(this).clone());
  • Anonymous
    Anonymous almost 12 years
    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.
  • Shawn
    Shawn over 11 years
    Has this been tested in all major browsers?
  • SpoonNZ
    SpoonNZ over 11 years
    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.
  • VoidKing
    VoidKing over 11 years
    @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 IE
  • tomfanning
    tomfanning over 11 years
    Hi Niraj. Welcome. This answer may well be correct but it could use some explanation.
  • mnsr
    mnsr over 11 years
    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(...);
  • Trindaz
    Trindaz over 11 years
    Looks almost identical to the very problem in the OP
  • nischayn22
    nischayn22 over 11 years
  • Timo Kähkönen
    Timo Kähkönen over 11 years
    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.
  • slipheed
    slipheed over 11 years
    @Timo, I've renamed the function to resetFormElement and added a note that you should preventDefault() on the button onclick.
  • cHao
    cHao about 11 years
    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.
  • e-info128
    e-info128 almost 11 years
    is not a ecmascript standard, the value of input type file is a protect property for security reasons.
  • Ninjakannon
    Ninjakannon almost 11 years
    @cHao, of course this is only true if the input element is actually in a form, which it does not have to be.
  • Gaurav Sharma
    Gaurav Sharma about 10 years
    doesn't work in chrome 34 (linux). replaceWith() method works in both browsers (chrome, firefox)
  • Ashish Ratan
    Ashish Ratan about 10 years
    ok but it will clear the entire form.. not specific file input
  • AlexB
    AlexB almost 10 years
    I don't understand why this answer isn't more upvoted ?!
  • kmacdonald
    kmacdonald over 9 years
    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.
  • TheCarver
    TheCarver over 9 years
    @AlexB: Because, as Timo explained, it's overkill just to clear one file input field.
  • Tisch
    Tisch over 8 years
    As many other posts on here explain, this isn't cross browser friendly.
  • PhiLho
    PhiLho over 8 years
    Latest Chrome doesn't like it (get(0) is undefined), I had to do .wrap('<form></form>'), as advised in jQuery doc anyway.
  • TheHamstring
    TheHamstring over 8 years
    For my understanding which browsers does this fail in?
  • Isaac
    Isaac over 8 years
    This isn't a good answer at all but the main problem was the really bad attitude
  • Lucky
    Lucky over 8 years
    Fails in Internet Explorer as input type file is readonly in IE>
  • Robo Robok
    Robo Robok over 8 years
    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-handler
  • fralbo
    fralbo about 8 years
    Don't know if that worked but no more on FF 45.0.2:(
  • JCollerton
    JCollerton almost 8 years
    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.
  • Andrei
    Andrei over 7 years
    $('input[type=file]').replaceWith($('input[type=file]').clon‌​e(true).val(''));
  • Robin Luiten
    Robin Luiten about 7 years
    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.
  • slipheed
    slipheed about 7 years
    @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.
  • Robin Luiten
    Robin Luiten about 7 years
    @slipheed 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.
  • naimul64
    naimul64 almost 7 years
    Works in chrome and firefox. More than enough.
  • Arsha
    Arsha over 6 years
    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.
  • QMaster
    QMaster over 5 years
    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.