Reputation: 98
This is the core part of the frontend code:
Input registration:
return (
<form onSubmit={handleSubmit(onSubmitForm)}>
<input {...register("image")} type="file" />
</form>
);
}
On form submit function:
const onSubmitForm = async data => {
axios.post("/api/products", data, { headers: { "Content-Type": "multipart/form-data" } });
};
In the browser console, the data object is: { image: FileList }
Code in the products API route is:
import { NextApiRequest, NextApiResponse } from "next";
export default (req: NextApiRequest, res: NextApiResponse) => {
console.log(req.body)
};
In the console, the result is: { image: { '0': {} } }
Upvotes: 2
Views: 8153
Reputation: 191
Set this in frontend for file selection and submit.
<input type="file" name="file" multiple id="files" onChange={onChangeFile} accept=".xlsx,.xls,image/*" />
<input type="button" onClick={submit}>Submit</button>
this function will fired on select files and stored in array.
let images=[];
const onChangeFile = (event) => {
for (let i = 0; i < event.target.files.length; i++) {
images.push(event.target.files[i]);
}
}
on submit the array which we define before will use to pass files data on NextJs API.
const submit = () => {
let data = new FormData();
images.forEach((element, i) => {
data.append("theFiles[]", element);
});
const res = await fetch(`${baseUrl}api/postmessage`, {
method: "POST",
headers: {
Accept: "multipart/form-data",
},
body: data,
});
const resData = await res.json();
}
1=> in your api/postmessage file use multer for uploading files or use other lib or packages.
2=> you have to give theFiles variable to multer with file limit for uploading.
3=> in upload block there is fileNameList variable which use for store uploaded file name (for unique name) and you can use that array for storing on DB after uploading files, you can see that on bottom of code.
import nextConnect from "next-connect";
import multer from "multer";
let fileNameList = [];
const upload = multer({
storage: multer.diskStorage({
destination: (req, file, cb) => {
let path ='./public/uploads/';
cb(null, path);
},
filename: (req, file, cb) => {
const ext = file.mimetype.split("/")[1];
let fileName = `${Date.now()}${Math.floor(
Math.random() * 100
)}.${ext}`;
cb(null, fileName);
fileNameList.push(fileName);
},
}),
limits: {
fileSize: 1024 * 1024 * 5,
},
}).array("theFiles[]", 5);
const apiRoute = nextConnect({
onError(error, req, res) {
res.json({
status: false,
data: [],
oth: `Sorry something Happened! ${error.message}`,
});
},
onNoMatch(req, res) {
res.json({
status: false,
data: [],
oth: `Method '${req.method}' Not Allowed`,
});
},
});
apiRoute.post(async (req, res) => {
await upload(req, res, function (err) {
if (err) {
return res.json({
status: false,
data: "File uploading faled."
});
}
});
fileNameList.map(async (fileName) => {
await sql_query(
"INSERT INTO images (imagename) VALUES(?)",
[fileName],
"insert"
);
});
});
export default apiRoute;
export const config = {
api: {
bodyParser: false,
},
};
Upvotes: 1
Reputation: 181
I also use react-hook-form, but in the case of image upload the truth is that this input leaves it out, I did not see it useful, my way of doing it was like this:
In the frontend, you should use something like this:
const fileChangedHandler = async (e) => {
const imageAvatar = new FormData()
imageAvatar.append(
"avatarImage",
e.target.files[0]
)
await Server.updateAvatarUser(auth.user.id, imageAvatar);
}
the input:
<label htmlFor="inputAvatar" >
Cambiar imagen
</label>
<input type="file" accept=".jpg, .jpeg, .png" id="inputAvatar" onChange={fileChangedHandler} className="hidden"/>
And in the backend I recomend you use a library like express-fileupload:
in your index.js with express in my case, add:
import fileUpload from "express-fileupload";
app.use(fileUpload());
and in your controller o your model:
const avatarImage = req.files.avatarImage;
const uploadPath = "public/images/avatars/" + avatarImage.name;
avatarImage.mv(uploadPath, function (error) {
if (error) {
console.log(error);
return { error: "Error guardando el archivo" };
}
});
return { success: "Archivo guardado" };
The above changes according to the library, you can also use multer.
I hope I have helped you with something, good luck.
Upvotes: 0