Add an image to a MongoDB collection using Vue, TypeScript, Express, and Multer

I'm trying to upload an image to my database, but I'm not quite sure if I'm doing this correctly.

Below is the code in my child component:

<script setup lang="ts">
import { ref } from 'vue';

const movieTitle = ref("");
const moviePoster = ref();

function fileInput(e: Event) {
    const inputElement = e.target as HTMLInputElement;

    const file = inputElement.files?.[0].name;
    if (file) {
        moviePoster.value = file;
        console.log("moviePoster", moviePoster.value);
    }
}

const emits = defineEmits<{ (e: "movieInfo", poster: FormData, title: string): void }>();

function emitImage() {
    if (!moviePoster.value) {
        return;
    }

    // Emit the "movieInfo" event with the poster and title
    emits("movieInfo", moviePoster.value, movieTitle.value);
}
</script>

<template>
  <div class="large-container">
    <div class="small-container">
        <form @submit.prevent="emitImage" enctype="multipart/form-data">
            <label for="file">Upload Movie Poster</label>
            <input type="file" @change="fileInput"/>
            <label for="movie-title-input">Movie Title</label>
            <input type="text" v-model="movieTitle" name="movie-title-input" />
            <button>Upload Image</button>
        </form>
    </div>
  </div>
</template>

In the parent component, the following code is present:

<script setup lang="ts">
    import AdminPageVue from '@/components/adminpage/AdminPage.vue';
    import axios from 'axios';
    import { ref } from 'vue';

    const savedMovie = ref<any>(null);

    async function saveMovieInfo(poster: FormData, movieTitle: string) {

        console.log("poster", poster, "title", movieTitle);

        const movieInfo = {
            poster: JSON.stringify(poster),
            title: movieTitle
        };

        console.log("movieInfo", movieInfo);

        try {
            const response = await axios.post("http://localhost:3000/movie/savemovie", movieInfo);
            console.log("Movie saved successfully!", response.data);

            const { poster, title } = response.data;

            console.log("poster", poster)

            savedMovie.value = {
                poster: poster,
                title: title,
            };

            console.log("savedMovie.value", savedMovie.value)

            
        } catch (error) {
            console.log("Failed to save movie:", error);
        }
    }
</script>

<template>
    <div>
      <AdminPageVue @movieInfo="saveMovieInfo"></AdminPageVue>
        <img :src="savedMovie.poster" alt="Uploaded Image" v-if="savedMovie" /> 
    </div>
</template>

In my express server, the mongoose schema looks like this:

const { default: mongoose } = require("mongoose");

const storedMovieInfo = mongoose.Schema({
    poster: String,
    title: String,
});

module.exports = mongoose.model("storedmovieinfo", storedMovieInfo);

For the movie.js router:

var express = require('express');
var router = express.Router();
const multer = require("multer");
const MovieModel = require ("../models/movie_model");

const upload = multer({storage});

router.post('/savemovie', upload.single("file"), async (req, res) => {
    const { title, poster } = req.body;
  
    const parsedPoster = JSON.parse(poster);
  
    console.log('poster', parsedPoster, 'title', title);
  
    try {
      const newMovie = await MovieModel.create({
        poster: parsedPoster,
        title: title,
      });
  
      console.log("newMovie", newMovie);
  
      res.status(201).json({
        poster: newMovie.poster,
        title: newMovie.title,
      });
    } catch (error) {
      console.log("Error saving movie:", error);
      res.status(500).json({ error: "Failed to save movie" });
    }
  });

module.exports = router;

When trying to retrieve the image from the database, there seems to be an issue where the browser cannot find the image, indicating a possible error in the process.

I attempted to save the image in the database for retrieval, but encountered difficulties.

Answer №1

An effective approach is to utilize the FormData method to transmit binary data to the backend for processing.

Within the child component:

<script setup lang="ts">
import { ref } from 'vue';

const movieTitle = ref("");
const moviePoster = ref<File>();


const fileInput = (e: Event): void => {
  const inputElement = <HTMLInputElement>e.target;

  const file = inputElement.files?.[0];

  if (file) {
    moviePoster.value = file;
  }
}

const emit = defineEmits<{
  (e: "movieInfo", poster: File, title: string): void
}>();

const emitImage = () => {
  if (!moviePoster.value) {
    return;
  }

  // Trigger the "movieInfo" event with the poster and title
  emit("movieInfo", moviePoster.value, movieTitle.value);
}
</script>

<template>
  <div class="large-container">
    <div class="small-container">
      <form @submit.prevent="emitImage" enctype="multipart/form-data">
        <label for="file">Upload the movie poster</label>
        <input type="file" accept="image/*" @change="fileInput"/>
        <label for="movie-title-input">Movie Title</label>
        <input type="text" v-model="movieTitle" name="movie-title-input" />
        <button>Upload image</button>
      </form>
    </div>
  </div>
</template>

Meanwhile, in the Parent component:

<script setup lang="ts">
import axios from 'axios';
import { ref } from 'vue';

import FileUploader from 'components/FileUploader.vue';

const savedMovie = ref<any>(null);

const saveMovieInfo = async (moviePoster: File, movieTitle: string) => {

  const formData = new FormData();
  formData.append('poster', moviePoster);
  formData.append('title', movieTitle);


  try {
    const response = await axios.post("http://localhost:3000/movie/savemovie", formData);
    console.log("Movie saved successfully!", response.data);

    const { poster, title } = response.data;

    console.log("poster", poster)

    savedMovie.value = {
      poster: poster,
      title: title,
    };

    console.log("savedMovie.value", savedMovie.value)


  } catch (error) {
    console.log("Failed to save movie:", error);
  }
}
</script>

<template>
  <div>
    <FileUploader @movieInfo="saveMovieInfo"></FileUploader>
    <img :src="savedMovie.poster" alt="Uploaded Image" v-if="savedMovie" />
  </div>
</template>

The backend should preferably provide either a base64 encoded string of the image or a URL (commonly from an S3 storage) where the image is stored. This can then be directly assigned to the src attribute, similar to how it is utilized in the parent component as

:src="savedMovie.poster"

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

Loading SVGs on the fly with Vue3 and Vite

Currently, I am in the process of transitioning my Vue2/Webpack application to Vue3/Vite. Here's an example of what works in Vue2/Webpack: <div v-html="require('!!html-loader!../../assets/icons/' + this.icon + '.svg')" ...

express middleware is not compatible with prototype functions

I've encountered a perplexing issue while working with the node.js express framework. Let's say I have a file called test.js containing the following code: function a(){ } a.prototype.b = function(){ this.c("asdsad"); } a.prototype.c = f ...

Implementing real-time search filter on JavaScript data with Vue.js

I have an array list that contains column names. I am trying to create a search filter that will dynamically select values from the array and display all rows and columns. The search filter should be based on the array containing column names. Column name ...

next-intl failing to identify the primary language setting

When testing next-intl for the app directory in the Next.js v13.4.0, I encountered an issue where the default locale was not recognized. Despite following the documentation step by step, I also faced significant challenges with the client-side version in p ...

The process of invoking the parent class's Symbol.iterator function from the child class's Symbol.iterator can be achieved by following a specific

I have two TypeScript classes defined below. class BaseIter { constructor(public a: number, public b: number, public c: number, public d: number){} *[Symbol.iterator](): Iterator<number> { yield this.a yield this.b yield this.c y ...

When executing a Node.js application on IBM Cloud Foundry, the files do not undergo compression

I am experiencing an issue with gzip compression when deploying my simple express app to cloud foundry. Locally, the js and css files are compressed, but once deployed, the file sizes remain the same. Does anyone know why this is happening or have a soluti ...

The promise was rejected and paused due to an exception, but no error was recorded

Check out this Node.js code snippet. I am using mongoose to query a MongoDB database. The code gets stuck at "Line A" with a message saying "Paused on Exception". There are no errors shown in the console. Strangely, this only happens when I run the code in ...

What is the method for incorporating a variable in MapReduce?

I have the following MapReduce script that I'm working with: splitAndGroupServices = function(groupMembers) { var mapFunction = function() { for(var idx in this.services) { var service = this.services[idx]; if(service.mem ...

Encountering a mongoose error when attempting to use the push()

var mongoose = require('mongoose'), Schema = mongoose.Schema, ObjectId = Schema.ObjectId; var SongSchema = new Schema({ name: {type: String, default: 'songname'}, link: {type: String, default: './data/train.mp3&a ...

Implementing the strictNullCheck flag with msbuild

Can strict null checks be enabled when compiling using msbuild? I see in the documentation that the compiler option is --strictNullChecks, but I couldn't find any specific entry for it on the msbuild config page. Is there a method to activate this f ...

Is there a way to define a specific HTTP Method for a particular route in express-unless?

Currently, I am utilizing express-jwt to control access to my API routes. app.use(expressJWT( { secret: process.env.JWT_PASSPHRASE }) .unless({ path: [ '/login', ...

What is the process for mocking a method from a class that is instantiated within another class using ts mockito in typescript?

I have a specific Class that I want to test using the mocha-chai testing framework in TypeScript. My approach involves incorporating ts-mockito for mocking purposes. export class MainClass implements IMainClass { private mainResource: IMainResource; ...

How to use $refs in Vue.js to update the content of a <span> element

In my <template>, I have a <span> element with the reference span-1. <span ref="span-1">my text</span> I am trying to update the content of this <span> from my text to my new text using $refs in my <script> se ...

What is the purpose of adding "/dist" to the library import statement?

Currently, I am in the process of developing a react component library using vite as my primary build tool. After successfully compiling the project and deploying it to the npm registry, I encountered an issue when importing it into my client app. Specifi ...

What is the best way to incorporate a mongoose model into another model?

I have two different models that I am working with. In the user model, I want to include an array of Requests, and in the Request Model, I want to have User as an attribute (without including the password). How can I achieve this? var userSchema = new S ...

Ways to convert monads within a conduit pipeline?

My current challenge involves transferring a file from disk to a File stored in MongoDB GridFS using the Database.MongoDB packages. main :: IO () main = do pipe <- MDB.connect (host "127.0.0.1") _ <- access pipe master "baseball" run close pip ...

Set up Angular 2 Universal on your system

Update: I attempted to set up Angular 2 Universal following this guide, but encountered errors when executing the command below. Here is the command I ran: typings install node express body-parser serve-static dexpress-serve-static-core mime --global -- ...

IDGenerator Vuex

One of the challenges I'm facing is creating unique identifiers for my components. I've been considering storing a global variable in Vuex, like lastGeneratedID: 0, along with a mutation to increment this value. The current solution involves co ...

Encountering an illegal invocation type error when clicking on the search icon within a Vue component

I keep encountering an "illegal invocation" error in the console whenever I try to click on the search icon. 'focus' called on an object that does not implement interface HTMLElement. This error seems to occur intermittently. <div class=" ...

The parent component is not re-rendered after a custom event is triggered in the child component causing interpolation to fail

Within my v-for loop, I am displaying a select element: <div v-for="(n, key) in selectedLanguages"> <select class="input input__col" v-model="currentLang[key]" @change="changeLanguage( ...