Cannot save image with multer and react - reactjs

I'm trying to send some string and an image to my db from a form in React component. Everything is saved, also the image name, but the file is not in the pubblic/images folder. My req.file is alway undefined and my data always an empty object
This is the Multer middleware
//Multer
const path = require("path");
const multer = require("multer");
const store = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "public/images");
},
filename: function (req, file, cb) {
cb(null, Date.now() + path.extname(file.originalname));
},
});
//Upload parameters
const upload = multer({
storage: store,
});
this is the post request of node
router.post("/", upload.single("image"), verify, async (req, res, next) => {
console.log(req.file);
const book = new Book({
title: req.body.title,
author: req.body.author,
image: req.body.image,
});
try {
const savedBook = await book.save();
res.send(savedBook);
} catch (error) {
res.send(error);
}
});
React
const token = useSelector((state) => state.token.token);
const data = new FormData();
//set Cover on change
const onChange = (e) => {
console.log(e.target);
data.append("image", e.target.files[0]);
console.log(data);
};
//Post Register
const Submit = async (e) => {
e.preventDefault();
await axios
.post(
"http://localhost:3000/api/book",
{
title: titleInput,
author: authorInput,
image: data,
},
{
headers: {
"auth-token": token,
},
}
)
.then((res) => {
console.log(res);
console.log(data);
})
.catch((error) => {
// handle error
console.log(error);
});
setAuthor("");
setTitle("");
};
Form
<form encType="multipart/form-data">
<input
type="text"
id="title"
value={titleInput}
name="title"
placeholder="title"
onChange={(e) => {
setTitle(e.target.value);
}}
/>
<input
type="text"
id="author"
value={authorInput}
name="author"
placeholder="Author"
onChange={(e) => {
setAuthor(e.target.value);
}}
/>
<input type="file" name="image" onChange={onChange} />
<button type="submit" onClick={Submit}>
Submit
</button>
</form>

Solved by changing the component code and sending data (create with Format()) to the node app.
//Post Register
const Submit = async (e) => {
e.preventDefault();
console.log(filename.name);
const data = new FormData();
data.append("author", authorInput);
data.append("title", titleInput);
data.append("image", filename);
data.append(
"imageTitle",
titleInput.split(" ").join("").toLowerCase() + ".jpg"
);
await axios
.post("http://localhost:3000/api/book", data, {
headers: {
"auth-token": token,
},
})
.then((res) => {
console.log(res);
})
.catch((error) => {
// handle error
console.log(error);
});
setAuthor("");
setTitle("");
};

Related

Graph Api Video Publish to Facebook Page not Working

I am trying to make an application that allows user to upload images and videos posts to the facebook page by uploading them to the application.
My access token and all other stuffs are working fine for uploading pictures, but not for videos.
const [file, setFile] = useState([]);
code for uploading picture (working)
const formData = new FormData();
formData.append("source", file)
axios.post("https://graph.facebook.com/<pageId>/photos?",
formData,
{
headers:
{
"Content-Type": "multipart/form-data",
"Authorization": "Bearer <access_token>"
}
}
).then(
(res) => {
if (res.data["id"]) {
alert("Upload Successfully")
}
}
).catch((err) => {
alert("Error communicating to server")
console.log(err)
})
code for uploading video (not working)
const formData = new FormData();
formData.append("file", file);
axios.post("https://graph-video.facebook.com/v16.0/<page_id>/videos",
formData,
{
headers:
{
"Content-Type": "multipart/form-data",
"Authorization": "Bearer <same_access_token>"
}
}
).then(
(res) => {
if (res.data["id"]) {
alert("Upload Successfully")
}
}
).catch((err) => {
alert("Error communicating to server")
console.log(err)
})
code for getting input
<input className="btn" type="file" accept="video/mp4,video/x-m4v,video/*"
onChange=
{
(e) => { handleChange(e) }
}
/>
<input className="btn" type="file" accept="image/png, image/jpeg"
onChange=
{
(e) => { handleChange(e) }
} />
const handleChange = (e) => {
setFile(e.target.files[0]);
}

Mulitple image add in react js

I am working on a project where I have one page where you should be able to add images. One by one it's worked perfectly. Now I want to make to be able to multiple add and upload. I don't want to use any library for image upload.
const onFileChange = (e) => {
const reader = new FileReader();
reader.onload = () => {
if (reader.readyState === 2) {
setPreview(reader.result);
}
};
reader.readAsDataURL(e.target.files[0]);
if (e.target.files[0]) {
setOver(true);
}
const copy = [...image];
copy.push(e.target.files[0]);
setImage([...copy]);
};
const onFileUpload = () => {
const formdata = new FormData();
image.forEach((elem) => {
formdata.append("data", elem);
});
formdata.append("id_grobnog_mjesta", Id);
addImage(formdata);
};
const addImage = async (data) => {
try {
setIsLoading(true);
const response = await apiRequest({
method: "post",
url: `spisak-srebrenica/upload`,
headers: {
Authorization: `Bearer ${token}`,
},
data,
});
if (response.data.success) {
getVictimImage();
}
setIsLoading(false);
setImage([]);
} catch (err) {
setIsLoading(false);
setImage([]);
}
};
Upload component :
<Upload>
<BiImageAdd size={50} opacity={0.5} />
<input type="file" onChange={onFileChange} />
<div className="items">
<p>Dodajte sliku</p>
<span className="format">PNG,JPG,GIF do 10MB</span>
</div>
</Upload>
add multiple attribute
<input type="file" id="files" name="files" multiple>
https://www.w3schools.com/tags/att_input_multiple.asp

Why does my upload to Cloudinary works but does not update the database?

I'm trying to upload a file to Cloudinary and save this file to a MongoDb database. The upload is working (I can see the new image in my Cloudinary account), but the db is not updated. The back end is built with Express. This is my code:
React function:
const { user, updateUser } = useContext(AuthContext)
const [imageUrl, setImageUrl] = useState("")
const navigate = useNavigate()
useEffect(() => {
axios
.get(`${API_URL}/users/user/${user._id}`)
.then(response => {
const { imageUrl } = response.data
setImageUrl(imageUrl)
})
.catch(err => console.log(err))
}, [user._id])
const handleFileUpload = e => {
e.preventDefault()
const uploadData = new FormData()
uploadData.append("imageUrl", e.target.files[0])
service
.uploadImage(uploadData)
.then(res => {
setImageUrl(res.secure_url)
})
.catch(err => console.log(err))
}
const handleSubmit = e => {
e.preventDefault()
const requestBody = { imageUrl }
if (imageUrl === "") {
return
}
axios
.put(`${API_URL}/users/edit-picture/${user._id}`, requestBody)
.then(res => {
updateUser(res.data)
navigate("/my-account")
})
.catch(err => console.log(err))
}
JSX:
<Form
onSubmit={handleSubmit}
>
<Input
type="file"
id="imageUrl"
onChange={handleFileUpload}
/>
<Button type="submit">Send</Button>
</Form>
updateUser function:
const updateUser = updatedUser => {
localStorage.setItem("user", JSON.stringify(updatedUser))
setUser(JSON.parse(localStorage.getItem("user")))
}
uploadImage function:
const uploadImage = file => {
return axios
.put(`${API_URL}/users/upload-picture`, file)
.then(res => res.data)
.catch(errorHandler)
}
And for the backend (where fileUploader is the Cloudinary config file):
router.put(
"/upload-picture",
fileUploader.single("imageUrl"),
(req, res, next) => {
if (!req.file) {
next(new Error("No file uploaded"))
return
}
res.json({ secure_url: req.file.path })
}
)
router.put("/edit-picture/:id", (req, res, next) => {
const { imageUrl } = req.body
const id = req.params.id
console.log(id)
User.findByIdAndUpdate(id, { imageUrl }, { new: true })
.then(updatedUser => {
res.status(200).json(updatedUser)
})
.catch(err => next(err))
})
Thanks for your help!
There seems to be some issue with your mongodb connection
Check wheather you are running mongodb locally and is it working properly
Check the mongodb URL that you would have used in express.Before integrating with react..check the API in postman or some other testing tool.

Image upload in mern stack using multer not working

I'm trying to upload image in MongoDB using multer and react but I'm unable to post it. I have three inputs in by form i.e title, content and image. If I try to post title and content only it is successfully being posted. I have also added "proxy": "http://localhost:8000", in frontend package.json file
Here is my form
function PostCreate() {
const [title, setTile] = useState("");
const [content, setContent] = useState("");
const [image, setImage] = useState({});
const dispatch = useDispatch();
const post = useSelector((state) => state.postReducer);
const fileOnChange = (e) => {
setImage(e.target.files[0]);
};
const submitPost = (e) => {
e.preventDefault();
const formData = new FormData();
formData.append("image", image);
dispatch(createPost(title, content, image));
};
return (
<div className="postCreate">
<h3 className="postCreate__heading">Create New Post</h3>
<div className="formBody">
<form onSubmit={submitPost}>
<div className="formInputs">
<label className="label">Title</label>
<input
className="titleInput"
type="text"
value={title}
onChange={(e) => setTile(e.target.value)}
placeholder="Enter the Title of the Post"
/>
</div>
<div className="formInputs">
<input type="file" onChange={fileOnChange} />
</div>
<div className="formInputs">
<label className="label">Content</label>
<textarea
className="titleInput"
type="text"
style={{
width: "1500px",
height: "500px",
color: "black",
outline: "none",
border: "none",
borderRadius: "6px",
}}
value={content}
onChange={(e) => setContent(e.target.value)}
/>
</div>
<div className="button">
<Button type="submit" variant="contained" color="primary">
Post
</Button>
</div>
{/* <button type="submit">Post</button> */}
</form>
Here is my action
export const createPost = (title, content, image) => async (dispatch) => {
try {
dispatch({ type: POST_POST_LOADING });
const config = { headers: { "Content-Type": "application/json" } };
const { data } = await axios.post(
"/api/newpost",
{ title, content },
config
);
dispatch({
type: POST_POST_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: POST_POST_FAIL,
payload: error,
});
}
};
Here is my postController
const createPost = async (req, res) => {
const { title, content, writer, comment, image } = req.body;
const fileType = req.file.mimetype.split("/")[1];
const newFileName = req.file.filename + "." + fileType;
fs.rename(
`uploads/images/${req.file.filename}`,
`uploads/images/${newFileName}`,
(req, res) => {
console.log("Renamed");
}
);
// const imageUrl = req.file.filename;
const newPost = await Post.create({
title,
content,
writer,
comment,
image,
// imageUrl,
});
if (newPost) {
res.send("Post created");
console.log("Post created");
} else {
res.status(201).send("Post not created");
console.log("Post not created");
}
};
Here is my routes
router.post("/newpost", upload.single("image"), createPost);
You're creating a form, which is a good start, but not sending it with axios.
To send a file from frontend to backend, you need to construct a form using FormData API and append the file to it. You can also append additional data to it.
Here is how I would change your code to work. In your form file:
const formData = new FormData();
formData.append('image', image);
formData.append('title', title);
formData.append('content', content);
dispatch(createPost(formData));
Then change your action to:
export const createPost = (formData) => async (dispatch) => {
try {
dispatch({ type: POST_POST_LOADING });
const config = { headers: { "Content-Type": "multipart/form-data" } };
const { data } = await axios.post(
"/api/newpost",
formData,
config
);
dispatch({
type: POST_POST_SUCCESS,
payload: data,
});
} catch (error) {
dispatch({
type: POST_POST_FAIL,
payload: error,
});
}
};

Displaying rest api response data in react

Here response data contains{name ,details} fields. I have a upload button to upload single/multi files. After uploading files, I don't refresh the page. Now for ex, I upload single file and displayed the response. Again I upload 2 files. Now I should be able to display response of current upload as well as previous one. It should be in the following format:
1.Name1
Details1
2. Name2
Details2
3. Name3
Details 3
this.state.list = this.state.list.concat(details);
this.state.list_name = this.state.list_name.concat(name);
< form onSubmit={this.handleSubmit} >
<label>
Upload a file: <br /><br />
<input type="file" name="file" multiple onChange{this.onChangeHandler}/>
</label>
<br /><br />
<button type="submit">
Upload</button>
</form >
<ol>
// {this.state.list_name.map((k) =>
// <li>{k} :</li>)}
//{this.state.list.map((k) =>
// <li>{k}</li>
// )}
</ol>
handleSubmit = (event) => {
event.preventDefault();
const formData = new FormData();
for (var x = 0; x < this.state.selectedFile.length; x++) {
formData.append('inputFile', this.state.selectedFile[x])
fetch('url', {
method: 'POST',
body: formData
}).then(res => {
return res.json()
})
.then((res) => {
this.setState({
details: res.data.details,
name: res.data.name
})
console.log("res data", res)
//console.log("Data is", res.data.name) //displays name in the console
})
.catch(error => console.log('ERROR message'))
}
};
I have commented the code that I have tried. Thanks in advance.
you can do this
remove this
this.state.list = this.state.list.concat(details);
this.state.list_name = this.state.list_name.concat(name);
add this
fetch('url', {
method: 'POST',
body: formData
}).then(res => {
return res.json()
})
.then((res) => {
const list = this.state.list;
list.concat(res.data.details);
const list_name = this.state.list_name;
list_name.concat(name);
this.setState({
list,
list_name,
details: res.data.details,
name: res.data.name
})
console.log("res data", res)
//console.log("Data is", res.data.name) //displays name in the console
})
.catch(error => console.log('ERROR message'))
}

Resources