Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Download image with Express and show in Vue with AJAX

I encountered an issue, that maybe some of you have answer for. I have a dashboard-like app running on MEVN Stack. I want the user to be able to upload his image and store it in backend server, because as I understood, it is not possible to upload to VueJS project public folder directly.

So I found a way to upload it thanks to some post I found here. But I cannot find a way back. My image is store on my backend server and I want to get it using axios in blob form and display it in VueJS. It should be pretty simple but there something I may missed.

First I get the name of my image file and send it like this with Express: res.sendfile(path.join(__dirname,"../../images/societies/",result.img_link));

I also return a default image url if there is no image, which works fine, but not the fetched images. The problem is I cannot access the image directly using URL, it is not accessible. So I have to find a way to get it as a blob I guess and display it.

Here is the code I use to get my Image in frontend, VueJS (script part):

getSocietyImage(society) {
    if(society.image){
      this.$http
        .get(this.apiUrl + "society/getImg/" + society.id)
        .then(image => {
          return image.data
        })
        .catch(err => {
          console.log(err)
        })
    }else{
        return this.basicImgUrl
    }
}

Here is the code in the template part which is a part of a v-for directive:

<img
    :src="getSocietyImage(society)"
    alt="content-img"
    class="responsive card-img-top"
/>

Below is what I get from the request from a console.log(): request_result

Thanks everyone for your help!

like image 744
Jonathan Mondaut Avatar asked Sep 21 '25 09:09

Jonathan Mondaut


1 Answers

Problem 1: Template methods

You shouldn't bind to methods. The method will run every time the template is re-rendered, which means whenever some relevant data changes.

Problem 2: Template async

Template rendering is synchronous, which means you can't bind to an async method at all. You should use a lifecycle hook (this example uses a URL):

new Vue({
  el: "#app",
  data() {
    return {
      myimage: null
    }
  },
  methods: {
    async getImage() {
      // Just a mockup of returning something async
      return await 'https://stackoverflow.design/assets/img/logos/so/logo-stackoverflow.svg';
    }   
  },
  async created() {
    this.myimage = await this.getImage();
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <img :src="myimage">
</div>

Problem 3: Binary data in HTML

You can either send back the raw binary or convert to base 64

3a. Raw binary (Use a blob)

Server

res.sendFile(file);  // Send raw binary

Browser

<img :src="myimage" />
async created() {
  const { data } = await this.getImage(); // Binary from server
  const blob = new Blob([data]);
  this.myimage = URL.createObjectURL(blob);
}

Note: Don't forget to clean up with URL.revokeObjectURL

3b. Base64

Or you could convert the binary to Base64 with Express first (but Base64 takes up about ~33% more bandwidth than binary):

Server

const bitmap = fs.readFileSync(file);
const base64 = new Buffer.from(bitmap).toString("base64");
res.send(base64);  // Send base64 instead of the raw file binary

Browser

<img :src="myimage" />
async created() {
  const { data } = await this.getImage(); // base64 data from server
  this.myimage = 'data:image/png;base64,' + data;
}
like image 148
Dan Avatar answered Sep 22 '25 23:09

Dan