はじめに
JavaScriptでローカルファイルを読み込む場合、同じファイルをもう一度読み込もうとしても、必要なイベントが発火せずファイルを読み込むことができません。これは、その対処方法を検討したメモです。
ローカルファイルの読み込み
以下のプログラムはローカルのテキストファイルを読み込んで、ブラウザ上に表示するだけのサンプルプログラムです。clear
ボタンは表示しているテキストを消去します。
このChoose File
ボタンを押して適当なテキストファイルを読み込むと、画面上にその内容が表示されます。次にclear
ボタンでテキストを消去し、もう一度Choose File
を押して先ほどと同じファイルをオープンしても何も表示されません。もちろん、違うファイルを指定すればきちんと表示されます。
これはブラウザが直前に読んだファイル名を覚えており、同じファイルだとchange
イベントを発火しないようにしているためです。
<!DOCTYPE html>
<html lang="jp">
<head>
<title></title>
<meta charset="UTF-8">
<script>
function fileInput(e) {
for (var i = 0, f; f = e.target.files[i]; i++) {
if (!f.type.match('text')) continue;
var reader = new FileReader();
reader.onload = function(e) {
var result = document.getElementById('result');
result.innerText = e.target.result;
};
reader.readAsText(f);
}
}
function clearResult() {
document.getElementById('result').innerText = '';
}
window.addEventListener('DOMContentLoaded', function() {
document.getElementById('fileinput').addEventListener('change', fileInput);
document.getElementById('clear').addEventListener('click', clearResult);
});
</script>
</head>
<body>
<input type="file" name="fileinput" id="fileinput" value="">
<input type="button" name="clear" value="clear" id="clear">
<div id="result"></div>
</body>
</html>
対処方法
直前に読み込んだファイル名を消すことができれば、もう一度同じファイルを読み込めそうです。ただ、change
イベントが発火しないので、上記のコードではそもそもChoose File
のボタンを押されたことも拾うこともできません。
そこで、ボタンが押されたことを検出するためにclick
イベントを使います。click
イベントはchange
イベントより前に起きるので、この中で対処できればchange
イベントも発火しそうです。調べてみるとthis.value
がファイル名を保持しているので、これをnull
にします。これで、同じファイルをもう一度読むことができるようになりました。
完成版のコードは以下のとおりです。
<!DOCTYPE html>
<html lang="jp">
<head>
<title></title>
<meta charset="UTF-8">
<script>
function fileInput(e) {
for (var i = 0, f; f = e.target.files[i]; i++) {
if (!f.type.match('text')) continue;
var reader = new FileReader();
reader.onload = function(e) {
var result = document.getElementById('result');
result.innerText = e.target.result;
};
reader.readAsText(f);
}
}
function clearResult() {
document.getElementById('result').innerText = '';
}
// 保持しているファイル名を消す
function clearFilePath(e) {
this.value = null;
}
window.addEventListener('DOMContentLoaded', function() {
document.getElementById('fileinput').addEventListener('change', fileInput);
document.getElementById('fileinput').addEventListener('click', clearFilePath);
document.getElementById('clear').addEventListener('click', clearResult);
});
</script>
</head>
<body>
<input type="file" name="fileinput" id="fileinput" value="">
<input type="button" name="clear" value="clear" id="clear">
<div id="result"></div>
</body>
</html>
終わりに
分かってしまえば簡単なことでしたが、実際のプログラムで起きたので悩んでしまいました。同じファイルは再読み込みしないという仕様は知りませんでした。
上記のコードはosxのsafariとchromeで試しています。