Reputation: 1
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
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
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:
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