I am working on a front end project where I want to store only 2 images, previousImage and nextImage, and show them on a div called previousWeek and nextWeek respectively.
I am using
// retrieve file input
document.querySelector("#input-image").addEventListener("change", function () {
// as localstorage only supports storing strings,
// we have to convert our image to a datURL
const reader=new FileReader();
reader.addEventListener("load",() => {
// localStorage.setItem("previous-image",reader.result);
console.log(reader.result);
});
for(var i=0;i<2;i++) {
reader.readAsDataURL(this.files[i]);
}
// reader.readAsDataURL(this.files[0]);
// console.log(this.files);
});
document.addEventListener("DOMContentLoaded", () => {
const recentImageDataURL = localStorage.getItem("recent-image");
if (recentImageDataURL) {
document.querySelector("#previousImage").setAttribute("src", recentImageDataURL);
}
});
to take input and show it previousImage div
How can I do the same, but store the next input in local storage as 'next-image'?
What I've tried
Using another readAsDataUrl for the next input in the this.files
using
reader.readAsDataURL(this.files[1]);
then setting item in localstorage using
localStorage.setItem("next-image",reader.result);
That gives me the error
script.js:30 Uncaught TypeError: Failed to execute 'readAsDataURL' on 'FileReader': parameter 1 is not of type 'Blob'.
TLDR: I want to store only 2 images in local storage, and i only have 1 input html element
<input type='file' accept='image/*' id="input-image">
from which I'm reading both images
The OP's problem is due to the FileReader
instance's method readAsDataURL
.
This process is blocking and can not be used on a reader instance by continuously plainly invoking it without triggering errors.
Thus one either looks for a promised based solution or as for the OP's event based approach one turns the reader's load
handler into a function which manages both the continuous collection of base 64 image sources and its final local storage once all image data has been captured.
function storeBase64ImageSourcesLocally([ recent, next ]) {
const storageData = JSON
.stringify({ recent, next });
console.log({ recent, next, storageData });
// localStorage
// .setItem('base-64-image-sources', storageData);
}
function proceedWithReadFileAsDataURL(reader, files) {
if (files.length >= 1) {
reader
.readAsDataURL(files.shift());
}
}
function collectBase64ImageSourceFromBoundData() {
const { reader, sources: { files, images } } = this;
const base64ImageSource = reader.result;
images
.push(base64ImageSource);
console.log({ images });
if (images.length >= 2) {
storeBase64ImageSourcesLocally(images);
}
// continue with the `readAsDataURL` process
// which is blocking and can not just be invoked
// continuously on `reader` one after the other.
proceedWithReadFileAsDataURL(reader, files);
}
function collectAndStoreBase64ImageData({ currentTarget }) {
let { files } = currentTarget;
// just in case of minimum two selected files.
if (files?.length >= 2) {
files = [...files]
// limit the iterable files to just 2.
.slice(0, 2);
const reader = new FileReader();
reader
.addEventListener(
'load',
collectBase64ImageSourceFromBoundData
.bind({ reader, sources: { files, images: [] } }),
);
// initially trigger the `readAsDataURL` process
// which is blocking and can not just be invoked
// continuously on `reader` one after the other.
proceedWithReadFileAsDataURL(reader, files);
}
}
document
.querySelector('#input-image')
.addEventListener('change', collectAndStoreBase64ImageData);
body { margin: 0; }
label > span { display: block; margin: 0 0 6px 0; }
.as-console-wrapper { max-height: 70%!important; top: auto; }
<label>
<span>Feel encouraged to select at least 2 image files ...</span>
<input type="file" multiple accept="image/*" id="input-image" />
</label>