MERN Stack - Deleting Item with API - node.js

I cannot figure out what I am doing wrong here.
I am using the MERN stack and using Axios for HTTP requests. Ideally I would like to have a modal pop-up as well to confirm the deletion but just solving the delete function is driving me crazy. I am new to the MERN stack and it seems overly complicated for some of the simple tasks I am trying to accomplish. Any input helps, thanks in advance.
GitHub Link
My API is working in Postman:
workorderRoutes.route("/:id").delete(function(req, res) {
WorkOrder.findById(req.params.id)
.then(workorder => workorder.remove().then(() => res.json({ success: true })))
.catch(err => res.status(404).json({ success: false }));
});
Below is the component I'm using:
import React, { Component } from "react";
import { Link } from "react-router-dom";
import axios from "axios";
const WorkOrder = props => (
<tr>
<td className={props.workorder.workorder_completed ? "completed" : ""}>{props.workorder.workorder_po}</td>
<td className={props.workorder.workorder_completed ? "completed" : ""}>{props.workorder.workorder_name}</td>
<td className={props.workorder.workorder_completed ? "completed" : ""}>{props.workorder.workorder_status}</td>
<td className={props.workorder.workorder_completed ? "completed" : ""}>{props.workorder.workorder_shippingFrom}</td>
<td className={props.workorder.workorder_completed ? "completed" : ""}>{props.workorder.workorder_completionDate}</td>
<td>
<Link className="btn btn-sm btn-primary" to={"/edit/" + props.workorder._id}>
Edit
</Link>
<button className="btn btn-sm btn-danger" to={"/" + props.workorder._id}>
Remove
</button>
<a className={props.workorder.workorder_completed ? "btn btn-sm btn-info" : "invisible"} href={"https://tools.usps.com/go/TrackConfirmAction?tRef=fullpage&tLc=2&text28777=&tLabels=" + props.workorder.workorder_tracking + "%2C"} target="_blank">
Tracking
</a>
</td>
</tr>
);
export default class WorkOrdersList extends Component {
constructor(props) {
super(props);
this.state = { workorders: [] };
}
componentDidMount() {
axios
.get("http://matthicksdev.com:4000/workorders/")
.then(response => {
this.setState({ workorders: response.data });
})
.catch(function(error) {
console.log(error);
});
}
componentDidUpdate() {
axios
.get("http://matthicksdev.com:4000/workorders/")
.then(response => {
this.setState({ workorders: response.data });
})
.catch(function(error) {
console.log(error);
});
}
workorderList() {
return this.state.workorders.map(function(currentWorkOrder, i) {
return <WorkOrder workorder={currentWorkOrder} key={i} />;
});
}
render() {
return (
<div>
<h3>Work Order Status List</h3>
<table className="table table-sm table-striped table-dark" style={{ marginTop: 20 }}>
<thead>
<tr>
<th>Job ID</th>
<th>Name</th>
<th>Status</th>
<th>Shipping From</th>
<th>Completion/Ship Date</th>
<th>Actions</th>
</tr>
</thead>
<tbody>{this.workorderList()}</tbody>
</table>
</div>
);
}
}
For the life of me I can't seem to figure out how to make the entries delete from the MongoDB.

Related

Csv data from Papa parse to React / useState to Node to MongoDB Atlas. insertMany

I implemented papa parse in React for the user to be able to upload the contents of a csv file into MongoDB (Atlas). Papa parse converts the Csv (with mulitple entries) into a json file which is then stored into a useState in React. Now I am trying to get this json data into MongoDB using Node/Express. It works flawlessly posting with Postman but not with React. So I guess it should be some mistake in the userFunctions.js or CSVReader.js file. Any help will be much appreciated!
// userFunctions.js
export const dataUpload = data => {
return axios.post('http://localhost:3002/event/create', {
seriennummer : data.seriennummer,
bezeichnung : data.bezeichnung,
verkaufspreis : data.verkaufspreis,
besonderheiten : data.besonderheiten,
})
.then(res => console.log('event created'))
.catch(err => console.log(err))
}
// CSVReader.js
const CSVReader = () => {
const [parsedCsvData, setParsedCsvData] = useState();
const parseFile = (file) => {
Papa.parse(file, {
header: true,
complete: (results) => {
setParsedCsvData(results.data);
},
});
};
console.log(parsedCsvData);
const onDrop = useCallback((acceptedFiles) => {
if (acceptedFiles.length) {
parseFile(acceptedFiles[0]);
}
}, []);
const {
getRootProps,
getInputProps,
isDragActive,
isDragAccept,
isDragReject,
} = useDropzone({
onDrop,
accept: "text/csv",
});
const createEvent = (e) => {
const newEvent = {
seriennummer : parsedCsvData,
bezeichnung : parsedCsvData,
verkaufspreis : parsedCsvData,
besonderheiten : parsedCsvData,
}
dataUpload(newEvent)
}
return (
<div>
<GlobalStyles />
<section
className="jumbotron breadcumb no-bg"
style={{ backgroundImage: `url(${"./img/background/subheader.jpg"})` }}
>
<div className="mainbreadcumb">
<div className="container">
<div className="row m-10-hor">
<div className="col-12">
<h1 className="text-center">CSV Datei hochladen - Uhren</h1>
</div>
</div>
</div>
</div>
</section>
<section className="container">
<div className="row">
<div className="col-lg-7 offset-lg-1 mb-5"></div>
<div
{...getRootProps({
className: `dropzone
${isDragAccept && "dropzoneAccept"}
${isDragReject && "dropzoneReject"}`,
})}
>
<input {...getInputProps()} />
{isDragActive ? (
<p>Drop the files here ...</p>
) : (
<h3>
<p>
Drag and Drop CSV File Here
</p>
</h3>
)}
</div>
<div>
<button type="submit" onClick={createEvent} class="form-control btn btnSign submit fs-3 ">CREATE NOW</button>
<div className="spacer-10"></div>
<div className="spacer-10"></div>
<table className="lead">
<thead>
<tr>
<th>Seriennummer</th>
<th>Firma</th>
<th>Preis</th>
<th>Besonderheiten</th>
</tr>
</thead>
<tbody>
{parsedCsvData &&
parsedCsvData.map((parsedData, index) => (
<tr key={index}>
<td>{parsedData.seriennummer}</td>
<td>{parsedData.bezeichnung}</td>
<td>{parsedData.verkaufspreis}</td>
<td>{parsedData.besonderheiten}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</section>
<Footer />
</div>
);
};
export default CSVReader;
// Controller
const createEvent = async (req, res) => {
try {
const event = await Event.insertMany(req.body)
res.json({
msg: "Created Event",
success: true,
data: event,
});
} catch (err) {
console.log(err);
res.json({
success: false,
data: err,
});
}
};
![console.log of the useState parsedCsvData][1]
[1]: https://i.stack.imgur.com/v5jZg.png
![Nodejs console][2]
[2]: https://i.stack.imgur.com/iPNXP.png
based on this error message, I believe req.body is stringified JSON. You need to do const data = JSON.parse(req.body) or use body-parser with express

how to display image in react fetched from node js

import React, { Component } from "react";
import axios from "axios";
class DisplyDish extends Component {
state = { posts: [] };
componentDidMount() {
axios
.get("http://localhost:8888/api/v1/dish") //returns promise
.then(response => {
this.setState({ posts: response.data });
console.log("response:", response.data);
})
.catch(err => {
console.log("err:", err);
});
}
render() {
return (
<>
<table>
<tbody>
<tr>
<th>id</th>
<th>title</th>
<th>type</th>
<th>weight</th>
<th>originalPrice</th>
<th>offerPrice</th>
<th>description</th>
<th>quantity</th>
<th>status</th>
<th>rating</th>
<th>image</th>
</tr>
{this.state.posts.map(post => {
return (
<tr key={post.id}>
<td>{post.id}</td>
<td> {post.title}</td>
<td> {post.type}</td>
<td> {post.weight}</td>
<td>{post.originalPrice}</td>
<td>{post.offerPrice}</td>
<td>{post.description}</td>
<td>{post.quantity}</td>
<td>{post.status}</td>
<td>{post.rating}</td>
<td>
<img
src={"http://localhost:8888/api/v1/dish/" + post.image}
alt="image"
/>
</td>
</tr>
);
})}
</tbody>
</table>
</>
);
}
}
export default DisplyDish;
and this is what i'm getting in console
id: 3
​​
image: "uploads/dish/image_1581159803092.jpg"
​​

how to render image from nodejs to react js using axios

import React, { Component } from "react";
import axios from "axios";
import "./getForm.css";
class GetData extends Component {
state = { posts: [] };
componentDidMount() {
axios
.get("http://localhost:8888/api/v1/user") //returns promise
.then((response) => {
this.setState({ posts: response.data });
console.log("response:", response.data);
})
.catch((err) => {
console.log("err:", err);
});
}
render() {
return (
<>
<h1>Posts</h1>
<table>
<tbody>
<tr>
<th>id</th>
<th>name</th>
<th>email</th>
<th>mobile</th>
<th>status</th>
</tr>
{this.state.posts.map((post) => {
return (
<tr key={post.id}>
<td>{post.id}</td>
<td> {post.name}</td>
<td> {post.email}</td>
<td> {post.mobile}</td>
<td>
<img src={post.image} />
</td>
</tr>
);
})}
</tbody>
</table>
</>
);
}
}
export default GetData;
You can add routes for your photos into Node.js public folder:
...
app.use('/photos', express.static(__dirname + '/public/photos'));
...
Then return image_url from http://localhost:8888/api/v1/user, the URL can be like http://localhost:8888/api/v1/photos/your_image_name.jpg
In your React:
...
<img style={{width:500, height:500}} src={post.image_url)} />
...
Note: Assuming you have the image URL's on your server response.
The posts state is being mapped before you receive the response from your server on the initial render. You can add a loading state which is set to true initially and after the response.data is set in the posts state, you can set loading to false.
You can then conditionally render the whole component based on this loading state like this.
Here is a link to a working sandbox.
import React, { Component } from "react";
import axios from "axios";
class GetData extends Component {
state = { posts: [], loading: true };
componentDidMount() {
this.fetchUserData();
}
fetchUserData = async () => {
try {
const response = await axios.get("http://localhost:8888/api/v1/user");
this.setState({ posts: response.data, loading: false });
console.log(response.data);
} catch (error) {
this.setState({ loading: false });
console.log(error);
}
};
render() {
if (this.state.loading) {
return "Loading";
}
return (
<>
<h1>Posts</h1>
<table>
<tbody>
<tr>
<th>id</th>
<th>name</th>
<th>email</th>
<th>mobile</th>
<th>status</th>
</tr>
{this.state.posts.map((post) => {
return (
<tr key={post.id}>
<td>{post.id}</td>
<td> {post.name}</td>
<td> {post.email}</td>
<td> {post.mobile}</td>
<td>
<img src={post.image} />
</td>
</tr>
);
})}
</tbody>
</table>
</>
);
}
}
export default GetData;

Keeping an open connection in Node.js app

I want to create a module, which keeps an open connection to Flickr API and keeps on receiving new recent photos.
I've tried the 'agentkeepalive' node module, but cloudfront seems to block the requests. This is what my current module code looks like, obviously, the fetch now only runs once:
Server side
require('dotenv').config()
var Flickr = require('flickr-sdk')
var flickr = new Flickr(process.env.FLICKR_API_KEY)
var express = require('express')
var app = express()
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:3000')
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept',
)
next()
})
app.get('/fetch', function(req, res) {
(() =>
flickr.photos
.getRecent()
.then(result => {
return res.send(result.body.photos.photo)
})
.catch(err => {
console.error('Error: ', err)
}))()
})
const PORT = process.env.PORT || 5000
app.listen(PORT, () => console.log(`Server started on port ${PORT}`))
Client side
import './App.css'
import 'bootstrap/dist/css/bootstrap.css'
import React, { Component } from 'react'
import axios from 'axios'
export class App extends Component {
constructor(props) {
super(props)
this.state = {
fetchClicked: false,
photos: [],
}
}
onFetchClick = () => {
this.state.fetchClicked
? this.setState({ fetchClicked: false })
: this.setState({ fetchClicked: true }, () => {
axios.get('http://localhost:5000/fetch').then(response => {
this.setState({
photos: response.data,
})
})
})
}
render() {
const { fetchClicked } = this.state
return (
<div className="App p-5 bg-secondary">
<h1>Flickr Streamer </h1>
{fetchClicked ? (
<button className="btn btn-info" disabled>
Streaming...
</button>
) : (
<button className="btn btn-info " onClick={() => this.onFetchClick()}>
Start the stream!
</button>
)}
<div>{this.state.dataReceived}</div>
<table className="table table-dark mt-5">
<thead>
<tr>
<th scope="col">Photo</th>
<th scope="col">Title</th>
</tr>
</thead>
<tbody>
{this.state.photos.map(item => {
return (
<tr key={item.id}>
<td>
<img
src={`https://farm${item.farm}.staticflickr.com/${item.server}/${item.id}_${item.secret}.jpg`}
/>
</td>
<td scope="row" className="w-50">
{item.title || 'No name'}
</td>
</tr>
)
})}
</tbody>
</table>
</div>
)
}
}
export default App
Polling is usually the way to do this kind of thing. This is how I would do it:
fetch = () => axios.get('http://localhost:5000/fetch')
.then(({data}) => this.setState({ photos:data })
onFetchClick = () =>
this.setState({ fetchClicked: !this.state.fetchClicked }),
() => this.fetch()
.then(() => setInterval(() => this.fetch(), 15 * 1000))
This doesn't deal with the user clicking the button more than once, but if that callback only executes if the state changed, or you disable the button when it is clicked, that would be handled for you by that. Otherwise, you'd have to handle it.

Problem with displaying data in MERN. My list displays all data and should only show the one with the ID

Im trying to build a mini forum for a school project.
Im trying to achieve, when im clicking on the link which in this case in under "Title: Test Post 1" i want to go the post and only show the data, which had the same id.
The routes are working when you click the link it goes to the id, it just shows all the data.
Im having a issue with data, it is showing all "posts" instead of the post with the matching ID.
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';
const Post = props => (
<tr>
<td>{props.post.post_vote}</td>
<td>{props.post.post_title}</td>
<td>{props.post.post_question}</td>
<td>{props.post.post_name}</td>
<td>{props.post._id}</td>
</tr>
)
export default class ThePost extends Component {
constructor(props) {
super(props);
this.state = {
posts: []
};
}
componentDidMount() {
axios.get('http://localhost:8000/posts/')
.then(response => {
this.setState({posts: response.data})
})
.catch(function (error) {
console.log(error);
})
}
postPost() {
return this.state.posts.map(function(currentPost, i) {
return <Post post={currentPost} key={i} />;
});
}
render() {
return (
<div>
<h3>Question:</h3>
<table className="table table-striped" style={{ marginTop: 20 }}>
<thead>
<tr>
<th>Votes</th>
<th>Title</th>
<th>Question</th>
<th>Name</th>
<th>Id:</th>
</tr>
</thead>
<tbody>
{ this.postPost() }
</tbody>
</table>
<Link to="/"><button className="btn btn-primary">Back to posts</button></Link>
</div>
)
}
}
My app.js
<Switch>
<Route path="/" exact component={PostsList} />
<Route path="/create" component={CreatePost} />
<Route path="/posts/:id" component={ThePost} />
<Route path="/edit/:id" component={EditPost} />
</Switch>
My backend
postRoutes.route('/posts/:id').get(function(req, res) {
let id = req.params.id
Post.findById(id, function(err, post) {
res.json(post);
});
});
I think the problem is here, but im not sure.
postPost() {
return this.state.posts.map(function(currentPost, i) {
return <Post post={currentPost} key={i} />;
});
}
Can anyone help me?
get method with http request need to have id param,
componentDidMount() {
axios.get('http://localhost:8000/posts/'+this.props.match.params.id)
.then(response => {
this.setState({posts: response.data})
})
.catch(function (error) {
console.log(error);
})
}

Resources