Modermo
Modermo

Reputation: 1992

FileReader() inside Vue computed property does not work

I am trying to render a series of image thumbnails based on images that I drag onto the screen.

My data looks like this:

data() {
  return {
    files: [File1, File2, File3]
  }
}

...where each File is a blob.

Here is my computed property, that should just return me each File blobs result

thumbnails() {
  return files.map(file => {
    let reader = new FileReader();
    reader.readAsDataURL(file);

     return reader.result
  })
}

I then try to render on screen as:

<ul>
  <li v-for="thumbnail in thumbnails>
    <img :src="thumbnail">
  </li>
</ul>

It doesn't work.

What is extremely interesting, however, is that if I insert a breakpoint in the files.map(...), it does work! What am I missing?

Upvotes: 1

Views: 737

Answers (1)

Styx
Styx

Reputation: 10076

What am I missing?

The fact that FileReader.readAsDataURL() method is asynchronous.

I'd recommend you to rethink your flow, or you can use vue-async-computed package.

Using it you can write it liked this:

{
  asyncComputed: {
    thumbnails() {
      return Promise.all(this.files.map((file) => {
        return new Promise((resolve, reject) => {
          const reader = new FileReader();
          // handle success
          reader.addEventListener('load', () => {
            resolve(reader.result);
          }, false);
          // handle error
          reader.addEventListener('error', () => {
            reject();
          }, false);
          // reading file
          reader.readAsDataURL(file);
        });
      }));
    },
  }
}

Don't forget that until Promise.all is resolved the thumbnails will be null, so you should add check for that to your template.

Upvotes: 4

Related Questions