g4rf4z
g4rf4z

Reputation: 67

Upload an image from input | JavaScript VueJs

This is the first time I try to upload a file from a client (Vue.js), through a server (Node.js, Express.js) to a database (MongoDB).

I would like to do it without any library.

The logic I'm trying to implement is the following: user can upload a file from an input. This file (can only be an image) is encoded to base64. Then it is sent to the server and recorded in the database as a string. It actually works. Data provided are well recorded in the database. But it also generates these errors:

This error appears just after loading the image in the input. error

Theses errors appear just after submitting the form. error errors

<script setup>
import FormInputMolecule from "#/molecules/FormInput.vue";
import ButtonAtom from "#/atoms/Button.vue";

import { computed, ref } from "vue";
import { useRouter } from "vue-router";
import { useSkillStore } from "@/store/skillStore";
import { skillSchema } from "@/validations/skillSchema";
import { validationErrors, validateData } from "@/services/yup";

const router = useRouter();

const skillStore = useSkillStore();

const loading = computed(() => skillStore.loaders.createSkill);

const skillData = ref({
  name: null,
  image: null,
  progress: null,
});

const previewImage = async (event) => {
  const preview = document.getElementById("preview-image");
  skillData.value.image = event.target.files[0];
  if (skillData.value.image) {
    const imageUrl = URL.createObjectURL(skillData.value.image);
    preview.src = imageUrl;
  } else {
    preview.src = "";
  }
};

const toBase64 = (file) =>
  new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result);
    reader.onerror = (error) => reject(error);
  });

const resetError = (field) => {
  if (validationErrors.value.skillCreationForm?.[field]) {
    validationErrors.value.skillCreationForm[field] = null;
  }
};

const createSkill = async () => {
  try {
    validationErrors.value["skillCreationForm"] = {};
    const isValid = await validateData(
      ["skillCreationForm"],
      skillSchema,
      skillData.value
    );
    if (!isValid) return;
    skillData.value.image = await toBase64(skillData.value.image);
    skillData.value.progress = parseInt(skillData.value.progress);
    await skillStore.createSkill(skillData.value);
    console.log(skillData.value);
    router.push({ name: "skills" });
  } catch (error) {
    console.error(error);
  }
};
</script>
<template>
  <form @submit.prevent="createSkill">
    <form-input-molecule
      label="Compétence"
      id="name"
      name="name"
      v-model="skillData.name"
      placeholder="Exemple: JavaScript"
      :error-message="validationErrors.skillCreationForm?.name"
      @input="resetError('name')"
    ></form-input-molecule>
    <form-input-molecule
      label="Image"
      id="image"
      name="image"
      type="file"
      v-model="skillData.image"
      :error-message="validationErrors.skillCreationForm?.image"
      @change="previewImage"
      @input="resetError('image')"
    ></form-input-molecule>
    <img id="preview-image" width="100" />
    <form-input-molecule
      label="Progression"
      id="progress"
      name="progress"
      type="number"
      v-model="skillData.progress"
      placeholder="Exemple: 60"
      :min="0"
      :max="100"
      :error-message="validationErrors.skillCreationForm?.progress"
      @input="resetError('progress')"
    ></form-input-molecule>
    <div class="button-wrapper">
      <button-atom type="submit" :loading="loading">Créer</button-atom>
    </div>
  </form>
</template>

I really do not know where these errors are coming from. If you guys could please help me.

Upvotes: 0

Views: 101

Answers (1)

thezohaan
thezohaan

Reputation: 359

If you can put up this code in stackblitz etc with all your dependencies it might be easier for people to help you.

Nevertheless, based on the error messages you have received..regarding the first error...

You have used a v-model for input element which is skillData.image and in the createSkill function you are assigning it a base64 value

skillData.value.image = await toBase64(skillData.value.image);

I think the error is saying that this input field can only have the file name. So maybe you want to look at why you are doing this update. You can just store it in a const.

Regarding the second error, it seems that the Skills route is loading before the values required for that page are received. So maybe you can try to do a v-if in on the skills page to only load on data received. Unable to dig more as you have not shared that page.

Upvotes: 1

Related Questions