Laxman Aryal
Laxman Aryal

Reputation: 1

how can i upload array of the images with other form data using nextjs & save data to mongodb database and images to cloudinary or localhost?

i am trying to implement form submission logic in latest version of the nextjs. in my case i have some form input and file input which accept multiple files or images. now my requirement is i want to make api call in api/addDetails, then save the form data to mongodb database and images to either cloudinary or local server. i need to generate url of the each images and save it in database as well so when we make a get request we can fetch all the details from the database. i am sharing sample form and some logic as well. there could be more inputs but this will be enough for me to start. please consider me as your intern and share your help:).

i tried cloudinary, multer , formidable, all one by one and together as well. most of the time i had an issue like undefined header, critical dependency error, coffee-script error and many more. i am sharing you simple form with 3 inputs, help me to write backend code to handle api request. you can change any code you want in my frontend. just want to make it work for now.

"use client";
import axios from "axios";
import React, { FormEvent, useRef, useState } from "react";

const AddDetails= () => {
  const nameRef = useRef<HTMLInputElement>(null);
  const descriptionRef = useRef<HTMLInputElement>(null);
  const fileRef = useRef<HTMLInputElement>(null);

  const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    const nameInput = nameRef.current!;
    const descriptionInput = descriptionRef.current!;
    const fileInput = fileRef.current!;

    const formData = new FormData();
    for (const file of Array.from(fileInput.files ?? [])) {
      formData.append("files", file);
    }
    formData.append("name", nameInput.value);
    formData.append("description", descriptionInput.value);

    await axios.post("/api/addDetails", formData);
  };

  return (
    <>
      <form onSubmit={handleSubmit}>
        <input type="file" name="files" ref={fileRef} multiple />
        <label htmlFor="name" className="block text-sm font-medium ">
         Name
          </label>
        <input
          type="text"
          name="name"
          ref={nameRef}
          className="mt-1 p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 block w-full shadow-sm"
        />
         <label htmlFor="name" className="block text-sm font-medium ">
         Description
          </label>
        <input
          type="text"
          name="description"
          ref={descriptionRef}
          className="mt-1 p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 block w-full shadow-sm"
        />
        <button
          type="submit"
          className="px-2 py-1 rounded-md bg-violet-50 text-violet-500"
        >
          Upload
        </button>
      </form>
    </>
  );
};

export default AddDetails;

Thank You guys, Appreciated

Upvotes: 0

Views: 2621

Answers (2)

Ismail Vohra
Ismail Vohra

Reputation: 148

Ok so you might not need a backend if you plan on using cloudinary’s API. You were guessing correctly when you imported axios into your code. I tried to make use of whatever you provided in your code and here is my crude attempt at trying to solve your problem:

import axios from "axios";
import React, { FormEvent, useRef } from "react";

// Configure with your account
const cloudName = "cloud_name";
const unsignedUploadPreset = "unsigned_preset";

const AppDetails = () => {
  // Not using for now
  const nameRef = useRef<HTMLInputElement>(null);
  const descriptionRef = useRef<HTMLInputElement>(null);

  // For file upload
  const fileRef = useRef<HTMLInputElement>(null);

  const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    const fileInput = fileRef.current!;

    const files = Array.from(fileInput.files ?? []);

    try {
      // Iterating over the files and uploading each one
      for (const file of files) {
        // Adding data to the upload form
        const formData = new FormData();
        formData.append("file", file);
        formData.append("upload_preset", unsignedUploadPreset);
        formData.append("public_id", file.name); // Here i'm assigning the public_id to be the filename (this includes the file extension)

        const response = await axios.post(
          `https://api.cloudinary.com/v1_1/${cloudName}/upload`,
          formData
        );

        // You can access the url, public_id and other deets using the response
        console.log(response.data['public_id']);
        console.log(response.data['secure_url'])
      }
    } catch (error) {
      console.error(error);
      // Handle the error
    }
  };

  return (
    <>
      <form onSubmit={handleSubmit}>
        <input type="file" name="files" ref={fileRef} multiple />
        <label htmlFor="name" className="block text-sm font-medium">
          Name
        </label>
        <input
          type="text"
          name="name"
          ref={nameRef}
          className="mt-1 p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 block w-full shadow-sm"
        />
        <label htmlFor="name" className="block text-sm font-medium">
          Description
        </label>
        <input
          type="text"
          name="description"
          ref={descriptionRef}
          className="mt-1 p-2 border border-gray-300 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 block w-full shadow-sm"
        />
        <button
          type="submit"
          className="px-2 py-1 rounded-md bg-violet-50 text-violet-500"
        >
          Upload
        </button>
      </form>
      <div id="Main"></div>
    </>
  );
};

export default AppDetails;

Now onto the explanation. I’m using the axios library to make API calls to my Cloudinary cloud. But before making API calls, I’ve defined an unsigned upload preset in my cloud account. If you don’t know how to do that you can check out this link to learn how to make one. Now what I’m doing here is iterating over the files that have been selected for uploading. I create a FormData object for each of the files and add all the necessary parameters. Finally, I make an API call to upload the media to the cloud. You can refer to this page for more info.

With the code out of the way, because you want to save the data into your MongoDB database what you could do is create a function that does this for you. Because you have all the things you need, like the public_id and the secure_url, you could pass in the entire response object to a new function, extract what you need, then make the insertion call to add the data to your database.

Hope this helps.

Upvotes: -2

PixelCook
PixelCook

Reputation: 81

Sounds like you'll need to write a backend. Honestly, if you were my intern I would tell you to read the documentation and Google around for a bit. When you run into errors like you've mentioned it's time for more googling.

But generally here are the steps:

  • Set up your backend server using a framework of your choice (e.g., Express.js, Django, Flask, etc.).
  • Define a route on your backend server to handle the form submission. For example, in Express.js, you can use the post method to define a route for the "/api/addDetails" endpoint.
  • Extract the form data sent from the front end in your backend route. The form data includes the name, description, and files.
  • Handle the file uploads appropriately. You can use a file upload library or handle it manually. If you choose to handle it manually, you'll need to process the uploaded files and save them to your desired location.
  • Store the form data, including the file information, in your backend's storage or database.
  • Send a response back to the front end indicating the success or failure of the form submission.

Here's an example implementation using Node.js with Express.js:

const express = require('express');
const multer = require('multer');

const app = express();
const upload = multer({ dest: 'uploads/' }); // Set the destination folder for file uploads

app.post('/api/addDetails', upload.array('files'), (req, res) => {
  const { name, description } = req.body; // Extract the name and description from the form data
  const files = req.files; // Access the uploaded files

  // Process and save the files to your desired location
  // You can access each file's details using the `filename` and `path` properties

  // Store the form data and file information in your backend's storage or database

  res.status(200).json({ message: 'Form submitted successfully' });
});

app.listen(3000, () => {
  console.log('Backend server is running on port 3000');
});

Upvotes: 0

Related Questions