Image is not showing up on frontend after fetching from mongoDB - node.js

Hello i am working on my fyp and i am new to react js and node js i have successfully stored my image in mongoDB database when i upload the image the image is stored in a local storage in my case it is stored in a folder named "uploads" and the name of image is stored in database and when i try to fetch image by giving path of locally stored image + name stored in database it does not show any image rather it shows a broken image. the name of the image is stored in a variable name "profileImage" and it is retrieving from database properly. dont know what is the issue anyone here to guide me . Screenshot of output and code is attached for reference.
Code For Frontend and get api
import React, { useEffect,useState } from 'react';
import {useHistory} from "react-router-dom";
import axios from 'axios'
const About = () =>{
const history = useHistory();
const [id, setID] = useState('');
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [phone, setPhone] = useState('');
const [work, setWork] = useState('');
const [profileimage, setPimage] = useState('');
const CallAbtPageA=()=>{
axios.get('/about')
.then((res) => {
setID(res.data.id);
setName(res.data.name);
setEmail(res.data.email);
setPhone(res.data.phone);
setWork(res.data.work);
setPimage(res.data.photo);
})
.catch((error) => {
console.log(error);
history.push('/login');
});
}
useEffect(()=>{
CallAbtPageA();
});
return(
<div>
<form method="GET" encType="multipart/form-data">
<div> <h1 style={{display:'inline',color:'black'}}>ID:</h1> <p style={{display:'inline',fontSize:"35px"}}>{name}</p> </div>
<div> <h1 style={{display:'inline',color:'black'}}>Name:</h1> <p style={{display:'inline',fontSize:"35px"}}>{name}</p> </div>
<div> <h1 style={{display:'inline',color:'black'}}>EMAIL:</h1> <p style={{display:'inline',fontSize:"35px"}}>{email}</p> </div>
<div> <h1 style={{display:'inline',color:'black'}}>PHONE:</h1> <p style={{display:'inline',fontSize:"35px"}}>{phone}</p> </div>
<div> <h1 style={{display:'inline',color:'black'}}>WORK:</h1> <p style={{display:'inline',fontSize:"35px"}}>{work}</p> </div>
</form>
<div> <h1 style={{display:'inline',color:'black'}}>PROFILE PIC:</h1> <img src = {`./uploads/${profileimage}`} /> </div>
</div>
)
}
export default About;```
[![Screenshot of output][1]][1]
[1]: https://i.stack.imgur.com/oWtw4.png
[![Screenshot of Response is in below link][2]][2]
[2]: https://i.stack.imgur.com/pVPfi.png

It is because your uploads folder is not acccessed publicly. So, to resolve this you have to serve the folder as static in Express.
Try this in nodejs:
app.use('/uploads',express.static('uploads'))

what is your api backend? image is not found there because may be you are not serving your static image assets.

Related

Why React doesn't upload image to server?

I have an app using react and express on the backend and multer to manage the upload. The server side is running properly when I make tests using postman, but if trait to send an image from react the result is unexpected. In that case the file doesn't appear in the uploads folder, however with postman is immediatly.
UploadPage,jsx
const { register, handleSubmit } = useForm();
const onSubmit = async (data) => {
const formData = new FormData();
formData.append('petimage', data.petimage);
try {
const res = await axios.post('/api/petregister', formData);
console.log(res)
} catch (error) {
setError(error.response.data.error);
setTimeout(() => {
setError("");
}, 5000);
}
}
return (
<Container className="mt-5">
<Form onSubmit={handleSubmit(onSubmit)}>
<Form.Group controlId="formFile" className="mb-3">
<Form.Label>Imagen de tu Mascota</Form.Label>
<Form.Control type="file"
label="Select image"
name="petimage"
{...register("petimage")}
/>
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</Container>
Google Response
The fields with name petimage are the same that I expecified in the backend and used these in the postman tests.
Edit
const store = require('../middlewares/multer');
route.post('/petregister', store.array('petimage', 12), petregister);
The last section of code is the route that is linked with the multer midleware asigned to ssave the images.
When you are making a API call to the backend, it will upload the image to the specific folder that you are defining in the backend like :
const multer = require('multer');
const upload = multer({ dest: 'folder path' });
I think you are getting results unexpected because the name for the image you are giving in formData formData.append('petimage', data.petimage); i.e petimage, it should be the same in the multer fileupload method. You haven't shared the backend code. So, I'm hoping that it may be like this:
var fileUpload = upload.single('petimage'); when the name is the same it will work fine.
If the image is of big size, you can compress it. Please visit this link, it will help you for sure.
https://dev.to/franciscomendes10866/image-compression-with-node-js-4d7h
You can try:
Remove
formData.append('petimage', data.petimage);
and use instead
data.petimage.forEach(pet => formData.append("petimage", pet))
The solution was trait the image as an object. The code is the next:
Object.values(data.petimage).forEach(pet => formData.append('petimage', pet))
Then it worked as expected.

Unable to send api response data from express to react after refreshing the page

I'm learning react and node js with express framework and I'm working on a project where I need to retrieve API data from express to react.
I retrieved data from backend express js where I made a simple json value. My backend server.js code is given below.
server.js
const express = require('express')
const app = express()
const PORT = 3001;
app .get('/api/contents',(req,res)=>{
const contents=[
{
"id":0,
"heading":"Joshua Tree Overnight Adventure",
"content":"A sight in the blue sea..."
},
{
"id":1,
"heading":"Catch waves with an adventure guide",
"content":"Lorem.."
},
{
"id":2,
"heading":"Catch waves with an adventure guide",
"content":"Lorem epsum ..."
}
];
res.json(contents)
})
app.listen(PORT,()=>{
console.log("express server is running...")
})
In react app, I used axios to retrieve those values from backend and tried to pass the api values of content with id= 0 as props in "TheLatestArticles" component. I have updated proxy in package.json in react to connect backend. The below code is the mainhomepage component where it is enclosed with TheLatestArticles component with props value
MainHomePage.js
import axios from 'axios';
import {useState,useEffect} from 'react'
function MainHomePage(){
const [content,setContent]=useState([]);
useEffect(()=>{
const fetchPosts = async ()=>{
const res =await axios.get("/api/contents")
setContent(res.data)
console.log(res)
}
fetchPosts()
},[])
return (
<>
<TheLatestArticle content={content} />
</>
);
}
export default MainHomePage;
TheLatestArticle.js
import cardImage from "./../../Images/card.jpg"
import './TheLatestArticleCard.css';
const TheLatestArticleCard=(props)=>{
console.log(props)
return(
<>
<div className="card">
<div className="image">
<img src={cardImage} alt="cardimg"/>
</div>
<div className="content">
<p className="heading">{props.content.heading}</p>
<p className="body-content">{props.content.content}</p>
<div className="details">
<p className="details-info">Travel <span className="details-info-2">/ August 21 2017</span></p>
</div>
</div>
</div>
</>
)
}
export default TheLatestArticleCard;
When I run the application, It displayed all the api values in the screen given below.
I console.log the api values inside useEffect and it displayed all the api values perfectly.
But when I refresh the page, the api value became undefined and gave me this error
Can you please solve me this issue with the reason behind this error? Thanks a lot!
Try it like this
{(content && content.length > 0) && <TheLatestArticle content={content} />}
Since your API call is async there won't be any data in content initially. After a while, your API is called and data is fetched. Then you will have data. To prevent TheLatestArticle to blow up we add some conditions when to show that component. The error in the screenshot is when you try to use a property heading from content where content is empty.
Now with the condition, TheLatestArticle will not render until there is some data.
Update
You are using <TheLatestArticle content={content} /> and content is assumed to be an object. But as per your code, it's an array. If you are not already using content.map((c)=> <TheLatestArticle content={c} />) you should do that.

How to get file from input tag in react client side app

I am creating a react app that downloads youtube videos when given their URL. I am using this npm package to help download the files. I keep on getting the error:
TypeError: fs__WEBPACK_IMPORTED_MODULE_3___default.a.createWriteStream is not a function
I think the problem is that client-side requires that the user uploads a file and I'm not super sure how to do that. I know that I can use an input tag like:
<input
type="file"
id="fileInput"
name="UserFile"
onChange={this.handleClick(this.files)}
/>
Then, In my HandleClick method, I have to use ytdl(url).pipe("file inputted by user");
however, I do not know how to get the user's file from the input tag. I have left my recent code below. Please let me know if you guys need anymore information or if I was not clear about anything. Thank you!
import React from "react";
import "../../css/Widget.css";
import ytdl from "ytdl-core";
import fs from "fs";
// https://github.com/fent/node-ytdl-core
// npm install ytdl-core#latest
//const fs = require("fs");
//const ytdl = require("ytdl-core");
class VideoDownload extends React.Component {
constructor(props) {
super(props);
this.state = {
videoURL: "",
};
}
handleClick = (idk) => {
var input = this.refs.myInput;
//var url = input.value;
var url = "https://www.youtube.com/watch?v=OISEEL5eBqg";
//console.log(url);
let userInput = document.getElementById("fileInput");
//console.log("userInput: ", userInput);
console.log("idk: ", idk);
//ytdl(url).pipe(fs.createWriteStream("trial.flv"));
/*
need this:
ytdl(url).pipe("file that the user inputted")
*/
};
render() {
return (
<div className="VD-Main">
<h1>Video Downloader</h1>
<input
type="file"
id="fileInput"
name="myfile"
onChange={this.handleClick(this.files)}
/>
<input type="text" ref="myInput" placeholder="Enter Youtube URL" />
<input
className="inputButton"
type="button"
value="Enter Link"
onClick={this.handleClick}
/>
</div>
);
}
}
export default VideoDownload;
That's how you can do it
handleClick(event) {
const reader = new FileReader();
reader.onloadend = () => {
//handle 'reader.result' as you like
}
reader.readAsDataUrl(event.target.files[0]);
}

Rendering react component on express route

I have an application which uses the express server and the create-react-app front-end. The structure looks like this. ( Not including all the files in the structure - only the ones that matters )
Client-
build
etc
public
src-
assets
components-
landing-
landing.js
github-
github.js
steam-
steam.js
App.js
index.js
routes-
routes.js
index.js
My index.js file is starting the express server and is as following-
const express = require( 'express' );
const app = express();
const PORT = process.env.PORT || 5000;
require('./routes/routes')( app );
app.use( express.static( 'client/build' ));
app.listen( PORT, () => {
console.log( "Server is running on port 5000 " );
});
The route file on the server side is as follows-
module.exports = ( app ) => {
app.get( '/', ( req, res ) => {
console.log("Hello");
res.send( "Hello" );
});
app.get( '/steam', ( req, res ) => {
res.send( "Place for Steam!!");
});
app.get( '/github', ( req, res ) => {
res.send("Place for Github!!");
});
}
My app.js file
class App extends Component {
render() {
return (
<div className="App">
<BrowserRouter>
<div className="container">
<Route path="/" component={ Landing }/>
<Route path="/steam" exact component={ Steam } />
<Route path="/github" exact component={ Github } />
</div>
</BrowserRouter>
</div>
);
}
}
export default App;
On my client side, my main concerned file in landing.js which is as follows.
class Landing extends Component{
render(){
return(
<div className="container">
<div className="row">
<div className="col-md-6">
<div className="bg">
<img src="https://www.bleepstatic.com/content/hl-images/2016/12/23/Steam-Logo.jpg" alt="" />
<div className="overlay">
Steam Info
</div>
</div>
</div>
<div className="col-md-6">
<div className="bg">
<img src="https://linuxforlyf.files.wordpress.com/2017/10/github-universe1.jpg" alt="" />
<div className="overlay">
Github Info
</div>
</div>
</div>
</div>
</div>
)
}
}
export default Landing;
In the above component, the thing that i care about is the a tag which leads to the either /steam or /github express route, which is intentional cause i want to reload the page and on the page I am only getting the res.send data, which makes sense cause that's an express route. But I want to render my steam component on /steam route. ( same with github ). I was hoping my BrowserRouter in App.js would change the component based on the route, but It's not. I am, only getting the express data. How can I render my Steam react component on the express '/steam' route. Clearly I am mixing the server and client side in weird way.
Simply use res.render('index'); for all backend routes.
Here we are building a single-page app with react, which means there's only one entry file (only one html file, usually index.html), the page renders differently because our js code checks the url and decides what to show (which frontend route to use). They all happend after the browser receives the html file along with the js/css files included. All the backend has to do when receiving a page request, is to send the same html file (and js/css files after the html is parsed by browser). Of course for data/xhr requests and invalid requests, we need to send data and 404.html accordingly.

Extracting uploaded csv data with multer

I am porting a rails app over to use the MEEN stack (Mongo, Express, Ember, Node)
I have a function that takes an uploaded csv and extracts the data from it and uses the data to then form SQL queries to a database. For some reason I am having issues with accessing the uploaded csv data with multer.
My Router file
var quotes = require('../api/quote');
var cors = require('cors');
var sku = require('../api/tools/sku');
var multer = require('multer');
var upload = multer({ dest: 'uploads/' });
var util = require("util");
var fs = require("fs");
var corsOptions = {
origin: 'http://localhost:4200'
}
module.exports = function(router){
router.route('/quotes').post(cors(corsOptions),function(req,res){
console.log(req.body);
quotes.addQuote(req,res);
}).get(cors(corsOptions),function(req,res){
quotes.getAllQuotes(req,res);
});
router.route('*').get(cors(corsOptions), function(req,res){
res.sendFile('public/index.html',{root:'./'});
});
router.post('/tools/sku/reactivate',upload.single('csvdata'),function(req,res){
console.log(req.files);
console.log('handing request over to sku.reactivate');
sku.reactivate(req,res);
});
};
My handlebars file for the tools/sku/reactivate template
<div class="col-md-8 col-md-offset-2 text-center">
<h2 class="toolTitle">Reactivate SKUs</h2>
<p class="lead">CSV Should Contain 1 Column (SKU) Only</p>
{{file-upload enctype="multipart/form-data" type="file" url="/tools/sku/reactivate" class="center-block" accept="text/csv" name="csvdata"}}
</div>
i am getting Error: Unexpected field when I attempt to post the file upload to the /tools/sku/reactivate post route. I don't understand whats wrong with my code.
The issue was using the file-upload ember addon. As soon as I removed the handlebars component and just hardcoded a form as seen below, the file upload's successfully.
<div class="col-md-8 col-md-offset-2 text-center">
<h2 class="toolTitle">Reactivate SKUs</h2>
<p class="lead">CSV Should Contain 1 Column (SKU) Only</p>
<form action="/tools/sku/reactivate" method="POST" enctype="multipart/form-data">
<input class="center-block" type="file" name="csvdata">
<button type="submit" class="btn btn-md btn-danger">Submit</button>
</form>
</div>

Resources