Reputation: 42925
I am currently working on some small helper utility. The approach is an in-page web app which is typically loaded from the local file system. That all works. Inside that app I need to be able to load and process local files (storing and reloading a profile). That works so far, but I have a problem left where I would like to ask for help:
I am using the filereader.js wrapper around the html5 file reader API. Things work so far, I am able to select, read and process a file in-page. Great! I even can process several files one after another. However there is one problem where I don't know how to start debugging it: I can not read a specific file a second time. I can select it, sure, but it is not read, thus not processed. It looks like there are no events generated at all by the file reader API. This might be connected to either caching or the prior usage of the file not having been terminated by me correctly, I have no idea.
Here is the relevant code:
My FileReader JS function:
function FileReader( selector, options ) {
var options = $.extend({
clicked: function(){},
payload: function(){},
selected: function(){}
}, options||{} );
var widget = convert( selector );
var selector = widget.find( 'input:file');
function clicked( event ) {
event.stopPropagation();
// highlight button as user feedback
highlight();
// raise the file selection dialog
selector.click();
// signal action to element
options.clicked();
}
function convert( selector ) {
var widget = $( selector );
// create new content for widget
var hotspot = $( '<a class="hotspot">' + widget.html() + '</a>' ).bind( 'click', clicked );
var selector = $( '<input type="file" style="display:none;" />' );
// replace initial content of widget
widget.empty().append( $('<form />').append(selector).append(hotspot) );
widget.find( 'input:file' ).fileReaderJS( { accept: false,
readAsDefault: 'BinaryString',
on: { load: selected } } );
return widget;
}
function highlight() {
// flash button by changing the background color for 100 msecs
widget.css( 'background-color', 'whitesmoke' );
setTimeout( function(){ widget.css( 'background-color', 'transparent' ); }, 100 );
}
function selected( event, file ) {
// process payload
options.payload( event.target.result );
// signal event to controlling element
options.selected();
}
return {}
} // FileReader
This method is called with '#wProfileImport'
as value of the argument selector
, which actually works and converts the markup below
<span id="wProfileImport" class="control button">
<img src="assets/img/profile-import.png">
</span>
such that it contains a (hidden) file input tag which is used to fire the file selection dialog (which works fine):
<span id="wProfileImport" class="control button">
<form>
<input type="file" style="display:none">
</form>
<a class="hotspot">
<img src="assets/img/profile-import.png">
</a>
</span>
Now when clicking the image the file selector is fired, I can select a local file and its content is handed over to the options.payload
callback. As said all fine and working also for more than a single file one after another. The only problem that remains: being able to read in the same file again. No event is fired, no content read, nothing.
So my question is: what do I have to do the process a file a second time, if it is selected by the user?
Upvotes: 0
Views: 1248
Reputation: 57729
This has to do with how the onchange
event works in JavaScript.
If you have a text input and you type a word, let's say "bird"
. You unfocus the field, this will cause the onchange
event to trigger. If you then go back into the field and change the word, then without unfocussing change it back to "bird"
and then unfocus the onchange
event will not fire because the value didn't change.
Other events like onkeydown
and onfocus
will fire however.
See if you can find another event that you can use. Maybe onclick
or onfocus
. I do fear that these fire too early.
A workaround to to destroy the input
once you read the file and render a new one in it's place. This way if the user selects the same file it will count as an onchange
again.
Another possibility is to not use the onchange
event but do the process once you press a submit button. You can get a reference to the file with:
var file = document.getElementById("#the_file_input").files[0];
Upvotes: 1