Implementing Blob image rendering in Vue.js from a database

In my front-end development, I am utilizing Vue.js. On the backend, I have set up Node.js, Express, and PostgreSQL with Sequelize. One of the challenges I encountered involved storing an item in the database that includes a thumbnail image.

Database Model

const Item = sequelize.define('item', {
    id: {
        type: Sequelize.INTEGER,
        primaryKey: true,
        autoIncrement: true
    },
    name: {
        type: Sequelize.TEXT,
        allowNull: false,
    },

    image: {
        type: Sequelize.BLOB('long'),
        allowNull: true,
    },

The image is stored as a Blob in the database, which has raised some concerns regarding best practices.

When accessing the object containing the image in my Vue template using this.item.image, I noticed it was returning an Object of type Buffer.

https://i.sstatic.net/PRpaY.png

Adding to Database

To add the item to the database from the browser, I implemented the following code in my Vue template:

<label for="image" class="itemCreate__field itemCreate__field--image">
   <span class="itemCreate__fieldLabel">Image</span>
   <input id="file"  type="file" accept="image/*" @change="onFileChange"/>
    <img v-if="itemPreviewImage" :src="itemPreviewImage" />
 </label>

These HTML elements rely on the following methods:

onFileChange(evt) {
    const files = evt.target.files || evt.dataTransfer.files;
    if (!files.length) return;
    this.createImage(files[0]);

},
createImage(file) {
    const image = new Image();
    const reader = new FileReader();

    reader.onload = evt => {
        this.itemPreviewImage = evt.target.result;
        this.item.image = evt.target.result;
    }

    reader.readAsDataURL(file);
},

Within the vue template responsible for rendering the image, I included the following:

<div v-if="item.image">
    <img :src="imgUrl" alt="Picture of item"/>
</div>

Rendering from Database

I attempted several methods, none of which seemed to work correctly:

createObjectUrl sourced from here:

imgUrl(){
  const objUrl = window.URL.createObjectURL(new Blob(this.item.image.data));

  return objUrl;
}

Creating a base64 string as suggested here:

imgUrl(){
    const intArray = new Uint8Array(this.item.image.data);
    const reducedArray = intArray.reduce((data, byte) => data + String.fromCharCode(byte), '');

    const base64String = `data:image/png;base64, ${btoa(reducedArray)}`;

    return base64String;
}

Another attempt involved creating a new Uint8Array and obtaining an objectUrl (taken from here):

imgUrl(){
  const arrayBuffer = new Uint8Array(this.item.image);
  const blob  = new Blob([arrayBuffer], {type: "image/png"});

  return window.URL.createObjectURL(blob);
}

Despite these efforts, including experiments with FileReader, the images still appeared broken without any errors in the console.

My hypothesis is that the issue lies in how I am submitting the data to the database. Specifically, the File attached as a property in the Ajax request may require conversion to a different format.

Answer №1

Before proceeding, ensure that you have a valid base64 string by using this tool:

Next, consider implementing a getter for the Item model

const Item = sequelize.define('item', {
    ...
    image: {
        type: Sequelize.BLOB('long'),
        allowNull: true,
        get () { // define a getter
            const data = this.getDataValue('image')
            return data ? data.toString('base64') : ''
        },
        set(val) {
          this.setDataValue('image', val);
        }
    },
    ...
}

Computed property

imgURL () {
    return this.item.image
        ? 'data:image/png;charset=utf-8;base64,' + this.item.image 
        : '' // some default image

}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Conceal the scroll bar while the page preloader is active

Is there a way to hide the scroll bar while the preloader is loading on a webpage? I want to prevent users from scrolling until the preloader disappears. I have tried using CSS and setting the body overflow to hidden, but it's not working as expected. ...

Struggling to make button switch in my Spring Boot Application (e.g. from "Add to Cart" to "Remove")

My application allows users to add items to their cart, which are then persisted using Spring Data JPA and saved in a MySQL database. I am looking to change the text from "Add to Cart" to "Remove" when the button is clicked, and vice versa. I have attempt ...

Transferring data in PDF format through email with the help of PHPMailer and html2pdf

Having trouble sending PDF or PNG files over email despite multiple attempts. Despite reading countless articles on the topic, nothing seems to be working as suggested. Can anyone provide assistance? I am using PHPMailer along with html2pdf and html2canva ...

Cypress eliminating the "X-CSRFToken" header

There seems to be an issue with the Cypress test runner where it is removing X-CSRFToken from the request header, leading to a 403 Forbidden error. I have compared the headers between a manual run and a Cypress test run, and you can see the difference in t ...

What is the best way to display HTML code using Vue syntax that is retrieved from an Axios GET request

I am currently working on a project that involves a Symfony 5 and Vue 3 application. In this setup, a Symfony controller creates a form and provides its HTML through a JSON response. The code snippet below shows how the form HTML is returned as a string: i ...

What is the process of programmatically sorting a column in a Material UI DataGrid?

Hey there! I'm currently working on a DataGrid that has a column with a custom header, specifically a Select option. My goal is to have the column sorted in descending order every time a user selects an option from the dropdown menu. renderHeader: (pa ...

Why did my compilation process fail to include the style files despite compiling all other files successfully?

As English is not my first language, I kindly ask for your understanding with any typing mistakes. I have created a workspace with the image depicted here; Afterwards, I executed "tsc -p ." to compile my files; You can view the generated files here Unf ...

Looking to implement a search filter in a table using reactJS. Wanting to optimize the search bar to dynamically filter the data displayed in the table

I'm having trouble with my search bar that is not currently filtering the information in my table. I have set up a table and a search bar, but the search bar isn't working as expected. When I type something in the search box, nothing happens. I s ...

Using jQuery UI to trigger Highlight/Error animations

Apologies if this question seems obvious, but I can't seem to find a clear answer anywhere... Is there a way to add a highlight/error message similar to the ones on the bottom right of this page: http://jqueryui.com/themeroller/ by simply using a jQu ...

Encountering a failure when trying to run npm in a React project

I've removed the .lock file and node_modules, then reinstalled, but it's still not working. Can someone assist me with fixing this? npm ERR! gyp ERR! node -v v16.13.0 npm ERR! gyp ERR! node-gyp -v v8.2.0 npm ERR! gyp ERR! not ok npm ERR! node-pr ...

Ensure that at least one checkbox is selected by using custom validation in jQuery

My form has checkboxes for gender (male and female) and a set of checkboxes for days of the week (Monday to Sunday). I need to set validation rules so that at least one gender and one day is selected. Below is my jQuery code: $(document).ready(function( ...

Error: The function "this.state.data.map" is not defined in ReactJS

class Home extends Component { constructor(props) { super(props); this.state = { data: [], isLoaded: false, }; } componentDidMount() { fetch("https://reqres.in/api/users?page=2") .then((res) => res.json ...

Tips for incorporating padding into your Vuetify navbar

I attempted to apply padding to the Vuetify navbar using the px-number attribute, but unfortunately, it did not take effect. I included this code snippet, but the padding did not appear as expected: <v-app-bar color="deep-purple accent-4" dar ...

Tips for bringing in a local dependency using yarn

I currently have 2 ongoing projects: ProjectA: a front-end project built with Vue.js ProjectB: a JavaScript module that I intend to use as a library in Project A I successfully built ProjectB and proceeded to run yarn link In the package.json file of P ...

Increase the value of $index within the ng-repeat loop

Is there a way to increment the value of $index in ng-repeat by a specific amount? For example, if I want to display two values at a time, how can I ensure that the next iteration starts with the third value instead of the second value? <div ng-contr ...

Not enough tiles are being requested in Leafletjs with Vue.js

My map is experiencing loading issues, appearing like an incomplete puzzle with white gaps where tiles should be. It seems that only 6 images have been requested via GET-Request when there should be more. To view the requested tiles, visit: Requested Tile ...

The Discord Bot is displaying an error message labeled as "DiscordAPIError[50035]"

Here is the code in my ticket_system.js file: const { Client, MessageEmbed, MessageActionRow, MessageButton, Modal, TextInputComponent, } = require("discord.js"); const settings = require("./settings"); ...

Identifying the Nearest Div Id to the Clicked Element

When a link is clicked, I am trying to locate the nearest div element that has an id. In this specific scenario, the target divs would be either #Inputs or #Stages. For example, if Page1 through 4 is clicked, I want to store the id #Inputs in a variable. ...

Maximizing Particle Performance Using JavaScript

I am experimenting with creating particles in JavaScript for the first time, and I'm unsure if the code below is optimized. When I generate 100 particles on the screen, there isn't much of an FPS drop noticeable. However, when multiple clicks o ...

Unable to populate an HTML table with JSON data

Can you assist me in populating a table using data from a JSON response? [ { "id": 1, "firstName": "James", "nickNames": [ {} ] }, { "id": 2, "firstName": "Linda", "nickNames": [ { "id": 2, "na ...