Как определить «изменение» типа ввода = файл для того же файла?


132

Я хочу запускать событие, когда пользователь выбирает файл. Это .changeсработает, если пользователь каждый раз меняет файл.

Но я хочу запустить событие, если пользователь снова выберет тот же файл.

  1. Файл, выбранный пользователем A.jpg(срабатывает событие)
  2. Файл, выбранный пользователем B.jpg(срабатывает событие)
  3. Файл, выбранный пользователем B.jpg(событие не срабатывает, я хочу, чтобы он сработал)

Как мне это сделать?

Ответы:


78

Вы можете обмануть это. Удалите элемент файла и добавьте его в то же место при changeсобытии. Он будет стирать путь к файлу, делая его каждый раз изменяемым.

Пример на jsFiddle.

Или вы можете просто использовать .prop("value", ""), см. Этот пример на jsFiddle .

  • jQuery 1.6+ prop
  • Предыдущие версии attr

@Pekka: Не совсем так. Но он может просто приспособить это. Допустим, ему нужно опубликовать файл. После публикации он может вызвать функцию js, которая удалит и добавит новый селектор файлов. Это выполнимо.
BrunoLM

3
имейте в виду, что когда вы используете .attr("value", "")или .val("")(как предлагает @ wagner-leonardi ниже), Internet Explorer
запускает

4
поскольку «значение» является свойством, а не атрибутом ввода, рекомендуется использовать jQuery.prop("value", "")
Роджер Баррето,

70

Если вы пробовали .attr("value", "")и не работали, не паникуйте (как я)

просто сделай .val("")вместо этого, и все будет нормально


49

Вы можете просто обнулить путь к файлу каждый раз, когда пользователь нажимает на элемент управления. Теперь, даже если пользователь выберет тот же файл, будет запущено событие onchange .

<input id="file" onchange="file_changed(this)" onclick="this.value=null;" type="file" accept="*/*" />

2
Мне нужно было такое решение. Он действительно короткий и выполняет свою работу. Красиво мыслящий Мариуш Вязовски.
Джей Дхармендра Соланки

Другое решение - это изменение значения при изменении тега ввода. Но мы не ожидаем, что значение изменится после выбора файла.
songgeb

1
Круто, это лучше, чем удаление и повторное добавление элемента в дом, спасибо
Дэвид Дал Буско

24

Используйте событие onClick, чтобы очищать значение целевого ввода каждый раз, когда пользователь нажимает на поле. Это гарантирует, что событие onChange будет запущено и для того же файла. Сработало у меня :)

onInputClick = (event) => {
    event.target.value = ''
}

<input type="file" onChange={onFileChanged} onClick={onInputClick} />

Использование TypeScript

onInputClick = ( event: React.MouseEvent<HTMLInputElement, MouseEvent>) => {
    const element = event.target as HTMLInputElement
    element.value = ''
}

17

Я заставил это работать, очистив входное значение файла onClick, а затем разместив файл onChange. Это позволяет пользователю выбирать один и тот же файл дважды подряд и при этом сохранять событие изменения для отправки на сервер. В моем примере используется плагин формы jQuery .

$('input[type=file]').click(function(){
    $(this).attr("value", "");
})  
$('input[type=file]').change(function(){
    $('#my-form').ajaxSubmit(options);      
})

onClickсрабатывает раньше onChange, поэтому этот метод отлично подходит для меня.
iplus26 07

8

Эта работа для меня

<input type="file" onchange="function();this.value=null;return false;">

1
я полагаю, вы имели в виду что-то вроде функции () {this.value = null; вернуть ложь; }
Jacek Pietal

7

Решение VueJs

<input
                type="file"
                style="display: none;"
                ref="fileInput"
                accept="*"
                @change="onFilePicked"
                @click="$refs.fileInput.value=null"
>

1
Спасибо за этот вариант ответа
Coisox

5

Вдохновленный @braitsch, я использовал в своем AngularJS2 следующее input-file-component

<input id="file" onclick="onClick($event) onchange="onChange($event)" type="file" accept="*/*" />

export class InputFile {

    @Input()
    file:File|Blob;

    @Output()
    fileChange = new EventEmitter();

    onClick(event) {
        event.target.value=''
    }
    onChange(e){
        let files  = e.target.files;
        if(files.length){
            this.file = files[0];
        }
        else { this.file = null}
        this.fileChange.emit(this.file);
    }
}

Вот и onClick(event)спасли меня :-)


4

Вот найденное мной решение React-y, которое сработало для меня:

onClick={event => event.target.value = null}


3

Вероятно, самое простое, что вы можете сделать, - это установить значение пустой строки. Это заставляет его «изменять» файл каждый раз, даже если тот же файл выбирается снова.

<input type="file" value="" />


2

Если вы не хотите использовать jQuery

<form enctype='multipart/form-data'>
    <input onchange="alert(this.value); return false;" type='file'>
    <br>
    <input type='submit' value='Upload'>
</form>

Он отлично работает в Firefox, но для Chrome вам нужно добавить this.value=null;после предупреждения.


2

По умолчанию свойство value элемента ввода очищается после выбора файлов, если вход имеет несколько атрибутов. Если вы не очистите это свойство, событие «изменение» не будет запущено, если вы выберете тот же файл. Вы можете управлять этим поведением с помощью multipleатрибута.

<!-- will be cleared -->
<input type="file" onchange="yourFunction()" multiple/>
<!-- won't be cleared -->
<input type="file" onchange="yourFunction()"/>

Ссылка


1

Здесь нельзя развести changeогонь (правильное поведение, так как ничего не изменилось). Тем не менее, вы также можете связать click... хотя это может срабатывать слишком часто ... хотя между ними не так много золотой середины.

$("#fileID").bind("click change", function() {
  //do stuff
});

Кажется, вы просто повторяете его слова, а .click()не «стреляете при повторном выборе».
BrunoLM 05

@BrunoLM - Нет, это не так ... но я думаю, вы прочитали отрывок, где я говорю, что вы не можете этого сделать, clickэто как можно ближе.
Ник Крейвер

1

Создайте для входа событие щелчка и событие изменения. Событие щелчка очищает ввод, а событие изменения содержит код, который вы хотите выполнить.

Таким образом, событие щелчка будет пустым, когда вы нажмете кнопку ввода (до того, как откроются окна выбора файла), поэтому событие изменения всегда будет срабатывать, когда вы выбираете файл.

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

$("#input").change(function() {
  //Your code you want to execute!
});
<input id="input" type="file">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js">
</script>


0

Вы можете использовать, form.reset()чтобы очистить список входных файлов files. Это сбросит все поля до значений по умолчанию, но во многих случаях вы можете использовать только input type = 'file' в форме для загрузки файлов. В этом решении нет необходимости клонировать элемент и повторно перехватывать события.

Спасибо philiplehmann


0

Я столкнулся с той же проблемой, я просмотрел решения выше, но они не получили хорошего объяснения того, что на самом деле происходит.

Это решение я написал https://jsfiddle.net/r2wjp6u8/ , не делает много изменений в дереве DOM, оно просто меняет значения поля ввода. С точки зрения производительности он должен быть немного лучше.

Ссылка на скрипку: https://jsfiddle.net/r2wjp6u8/

<button id="btnSelectFile">Upload</button>

<!-- Not displaying the Inputfield because the design changes on each browser -->
<input type="file" id="fileInput" style="display: none;">
<p>
  Current File: <span id="currentFile"></span>
</p>
<hr>
<div class="log"></div>


<script>
// Get Logging Element
var log = document.querySelector('.log');

// Load the file input element.
var inputElement = document.getElementById('fileInput');
inputElement.addEventListener('change', currentFile);

// Add Click behavior to button
document.getElementById('btnSelectFile').addEventListener('click', selectFile);

function selectFile() {
  if (inputElement.files[0]) {
    // Check how manyf iles are selected and display filename
    log.innerHTML += '<p>Total files: ' + inputElement.files.length + '</p>'
    // Reset the Input Field
    log.innerHTML += '<p>Removing file: ' + inputElement.files[0].name + '</p>'
    inputElement.value = '';
    // Check how manyf iles are selected and display filename
    log.innerHTML += '<p>Total files: ' + inputElement.files.length + '</p>'
    log.innerHTML += '<hr>'
  }

  // Once we have a clean slide, open fiel select dialog.
  inputElement.click();
};

function currentFile() {
    // If Input Element has a file
  if (inputElement.files[0]) {
    document.getElementById('currentFile').innerHTML = inputElement.files[0].name;
  }
}

</scrip>

0

Таким образом, невозможно на 100% быть уверенным, что они выбирают один и тот же файл, если вы не сохраните каждый файл и не сравните их программно.

Способ взаимодействия с файлами (что делает JS, когда пользователь «загружает» файл) - это HTML5 File API и JS FileReader .

https://www.html5rocks.com/en/tutorials/file/dndfiles/

https://scotch.io/tutorials/use-the-html5-file-api-to-work-with-files-locally-in-the-browser

В этих руководствах показано, как записывать и читать метаданные (хранящиеся как объект js) при загрузке файла.

Создайте функцию, которая запускает onChange, которая будет читать-> хранить-> сравнивать метаданные текущего файла с предыдущими файлами. Затем вы можете инициировать свое событие, когда выбран нужный файл.


0

Поверьте, это вам точно поможет!

// there I have called two `onchange event functions` due to some different scenario processing.

<input type="file" class="selectImagesHandlerDialog" 
    name="selectImagesHandlerDialog" 
    onclick="this.value=null;" accept="image/x-png,image/gif,image/jpeg" multiple 
    onchange="delegateMultipleFilesSelectionAndOpen(event); disposeMultipleFilesSelections(this);" />


// delegating multiple files select and open
var delegateMultipleFilesSelectionAndOpen = function (evt) {

  if (!evt.target.files) return;

  var selectedPhotos = evt.target.files;
  // some continuous source

};


// explicitly removing file input value memory cache
var disposeMultipleFilesSelections = function () {
  this.val = null;
};

Надеюсь, это поможет многим из вас, ребята.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.