all articles

file input triggers no change event if file names are the same

2015-07-15 @sunderls

chrome IE fileinput change event js

description, bug

For <input type='file'>, if you select a file, and then select it again, it won't trigger 'change' event, of course.

But if you select a different file but with the same name&path;, Chrome & IE won't trigger 'change' event, while Firefox triggers it.

But if you submit the form with traditional forms, it won't be a problem, since even though 'change' event is not fired, the file attached to input is changed.

If you get file $fileInput[0].files[0].size, you will find it changed.

if you need to do something like preview or file validation, what should you do?

There is no event when file dialog is dismissed, we have to clear the file input and make the file input trigger 'change' every time.

flow: file change => do what you want => clear the file input

how to clear the file input

someone suggest $input.val('') on 'click'. Yes it may works, but it leaves no options to regret. If we click the input the second time, and cancel the dialog without selecting, the input will have no file attached, which is not optimal.

So I'd suggest using a newly generated input to replace the old one, and moving the old input to some where else in the form.

code

form example:

 <div class="fileUnit">
    <label><input class="realInputFile" name="name"></label>
 </div>

say we have some func to do the previewing or validating

function onchange(){
    //...do previewing or sth else
    fixFileInput();
}

we create a fix function, called at initializing and `onChange'

function fixFileInput(){
    var $realInput = $fileUnit.find('.realInputFile'),
        $fakeInput = $fileUnit.find('.fakeInputFile');

    // if this is the first load
    if ($fakeInput.size() === 0){
        $fakeInput = $realInput.clone();
        $fakeInput.removeClass('realInputFile').addClass('fakeInputFile');

        $realInput.before($fakeInput);
        $realInput.hide();
        $fileUnit.append($realInput);
        $fakeInput.on('change', onchange)
    } else {
        var $newInput = $fakeInput.clone();
        $fakeInput.before($newInput);
        $fakeInput.removeClass('fakeInputFile').addClass('realInputFile').hide()
        $realInput.replaceWith($fakeInput);
        $newInput.on('change', onchange);
    }
}

2017-04-24 added

seems that Chrome has updated, so just cloning is not enough, have to val('') to clear the file data before using

var $newInput = $fakeInput.clone();
$newInput.val('');