Using Javascript FileReader in forEach loop to append elements

Tags: ,



I am using the FileReader to insert HTML to a preview element. That parts works. However I need to manipulate the elements after they are inserted. When I try to select the inserted elements with (let previews = document.querySelectorAll(‘.fb-preview li’);) I get and empty node array.

I was under the impression that forEach is blocking and by the time the loop finishes I should be able to select the inserted html elements.

Is there something I am missing about the FileReader or forEach loops?

It works if I add a setTimeout but that seems hackish.

items.forEach(v => {               
    const preview = document.querySelector('.fb-preview');
    const reader = new FileReader();

    reader.addEventListener('load', () => {
        switch (v.type) {
            case 'application/pdf':
                preview.insertAdjacentHTML('beforeend', `<li><embed src=${reader.result}></i><span>${v.name}</span></li>`);
            break;
            case 'image/jpeg':
            case 'image/tiff':
            case 'image/gif':
            case 'image/png':
                preview.insertAdjacentHTML('beforeend', `<li><img src="${reader.result}"></i><span>${v.name}</span></li>`);
            break;
            default:
                preview.insertAdjacentHTML('beforeend', `<li><i class="fas fa-question-circle fa-fw"></i><span>${v.name}</span></li>`);
            break;
        }
    }, false);

    if (v) reader.readAsDataURL(v);        
});

let previews = document.querySelectorAll('.fb-preview li'); 
if (previews.length > 10) previews.forEach(e => e.style.height = '50%');
if (previews.length > 20) previews.forEach(e => e.style.height = '30%');
if (previews.length > 30) previews.forEach(e => e.style.height = '10%');

Answer

Your code shows that the DOM mutations happen in an event listener, which is asynchronous. The forEach loop only registers the listeners, it does not block while reading each files.

There is a better and easier way to accomplish your purpose: Blob URLs. You have a FileReader, so presumably you have Files to begin with ? File is a subclass of Blob, so you can use URL.createObjectURL on them. That gives you, synchronously, a relatively short “blob:” URL which references (but does not represent) the file’s contents. Use that as the source of your images and embeds.



Source: stackoverflow