Minimal WebComponent to parse file selectors into bytearrays
Extending the HTMLInputElement and using custom events for easy hooks
I’m in the process of moving the (non-wasm parts) of my web front-end for cega over to vanilla Jasvacript WebComponents. I’ve liked how much it cleans up and encapsulates the logic without even needing a framework. The hooks for parsing the file into a byte array on the client-side (for passing to the wasm) were an obvious extraction point, so I pulled it out to a gist micro-project: file-byte-reader.
This hides a lower-level abstraction with its own async, FileReader. It also makes a nice real world example of extending an input tag and using custom events to give easy hooks for your WebComponents. I liked the pattern Chris Ferdinandi was using for having a (partially) curried emit function to make dispatching your events more succinct, so I’ve added it to my practices for WebComponents going forward.
ETA: The code in this post may not get updates, so check the gist on the project page for the latest.
//attach a listener (to an `is` applied file selector) that will get the parsed byte array:
//<input is="file-byte-reader" id="file-input" type="file"
//$('#file-input').addEventListener("file-byte-reader:loaded", e => YOURHANDLER(e.detail));
class FileByteReader extends HTMLInputElement {
connectedCallback() {
this.addEventListener('change', this.onChange);
}
emit (type, detail = {}) {
let event = new CustomEvent(`file-byte-reader:${type}`, {
bubbles: false,
cancelable: false,
detail: detail
});
return this.dispatchEvent(event);
}
onFileLoad(event) {
this.emit('loaded', new Int8Array(event.target.result));
}
onChange() {
if (this.files.length == 0) { return }
Array.from(this.files).forEach(file => {
const fileReader = new FileReader();
fileReader.addEventListener('loadend', e => this.onFileLoad(e));
fileReader.readAsArrayBuffer(file);
});
}
}
customElements.define("file-byte-reader", FileByteReader, { extends: 'input'});