How to parse json response using fetch API - node.js

Am trying to display json response after calling an API using fetch, I can see the response in the response tab of chrome, but I can't find it in fetch response object
Client side
import React from 'react';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
query: '',
properties: []
}
this.search = this.search.bind(this);
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
const { name, value } = event.target;
// const { query } = this.state.query;
this.setState({
[name]: value
});
}
search() {
console.log('fetching data')
try {
fetch('http://localhost:3000/property/find', {
method: 'POST',
mode: 'CORS',
body: JSON.stringify({ "query": this.state.query }),
headers: {
'Content-Type': 'application/json'
}
}).then(res => res.json())
.then((data) => {
console.log(data)
this.setState({ properties: data.result });
})
}
catch (err) {
return err;
}
}
render() {
const { properties } = this.state;
return (
<div className="App" >
<input type="text" name="query" onChange={this.handleChange}></input>
<div className="form-group">
<button className="btn btn-primary" onClick={this.search}>Search</button>
</div>
<div className="row text-center">
{properties.items &&
properties.items.map((property, index) =>
<div className="col-lg-3 col-md-6 mb-4" key={index}>
<div className="card h-100">
<img className="card-img-top" src="http://placehold.it/500x325" alt="" />
<div className="card-body">
<h4 className="card-title"> {property.details.description}</h4>
{/* <p className="card-text">{property.biography}</p> */}
</div>
<div className="card-footer">
Find Out More!
</div>
</div>
</div>
)
}
</div>
</div>
)
}
}
export default App;
Server side
var app = express();
const server = http.createServer(app);
const io = socketIo(server);
var db = require('./db');
var property = require('./endpoint/property');
// var authController = require('./auth/AuthController');
app.use(function (req, res, next) {
// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3001');
// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
next();
});
//allow OPTIONS on just one resource
// app.post('*', cors())
app.use(cors())
app.use('/property', property);
End point response
var express = require('express');
var router = express.Router();
var bodyParser = require('body-parser');
router.use(bodyParser.urlencoded({ extended: true }));
router.use(bodyParser.json());
var Model = require('../model/propertyModel');
// GETS A SINGLE USER FROM THE DATABASE
router.post('/find',function (req, res) {
var query = req.body.query
console.log(query)
Model.find( { $text: { $search: query }} , { score: { $meta: "textScore" } }).sort( { score: { $meta: "textScore" } } ).then((data)=>{
if(data.length>0){
res.status(200).json({"result":data});
}
if (data.length==0){
Model.find({ "details.description": {$regex:query} }).sort( { score: { $meta: "textScore" } } ).then((data)=>{
if(data){
res.status(200).json({"result":data});
}
if (data.length==0) return res.status(404).send("No properties found.");
})
}
})
});

Inside your render method, if you change this:
{properties.items &&
properties.items.map((property, index) =>
...to this:
{properties &&
properties.map((property, index) =>
That should resolve this for you.

Within the render method, it looks like properties.items is expected to be an array. But in the network tab response screenshot, the result field inside the JSON response is an array.
Calling this.setState({ properties: data.result }); will lead to properties being the field you should be mapping over in the render method, instead of properties.items

Related

_id is missing after doing actions

i'm currently creating my first MERN App, and everything is going well, until something happened, and i'm going my try to explain because i need help !
What i'm doing is a facebook clone, where you can post something, you can delete your post and you can update your post, the logic is simple, i call dispatch to pass the data to the actions, the actions pass the data to the backend, and the backend return something to me and it saves in my store, because i'm using redux
The problem is that, when i have 2 post, and i want to delete a post, or maybe i want to edit it, the other post dissapears, it's like it loses its id and then loses the information, then i can't do anything but reaload the page, and it happens always
this is how it looks like, everything fine
Then, after trying to edit a post, the second one lost its information, and in the console, it says that Warning: Each child in a list should have a unique "key" prop, and i already gave each post the key={_id}, but the post lost it and i don't know how
Here's the code
Posts.js
import React, { useState } from "react";
import "./Posts.css";
import moment from "moment";
// Icons
import { BiDotsVertical, BiLike } from "react-icons/bi";
import { MdDeleteSweep } from "react-icons/md";
import { AiFillLike } from "react-icons/ai";
import { GrClose } from "react-icons/gr";
// Calling actions
import { deletePost, } from "../actions/posts.js";
// Gettin The Data From Redux
import { useSelector, useDispatch } from "react-redux";
const Posts = ({ setCurrentId }) => {
const [animation, setAnimation] = useState(false);
const [modal, setModal] = useState(false);
const [modalPost, setModalPost] = useState({});
// Getting The Posts
const posts = useSelector(state => state.posts);
const dispatch = useDispatch();
// Showing And Hiding Modal Window
const ModalWindow = post => {
setModalPost(post);
setModal(true);
};
// Liking the post
// const Like = id => {
// dispatch(giveLike(id));
// setAnimation(!animation);
// };
if (!posts.length) {
return <div>Loading</div>;
} else {
return (
<div className="Posts">
{/* // Modal window for better look to the post */}
{/* {modal && (
<div className="modalWindow">
<div className="container">
<div className="container-image">
<img src={modalPost.image} alt="" />
</div>
<div className="information">
<div className="container-information">
<div className="data-header">
<h2>
User <br />{" "}
<span style={{ fontWeight: "400" }}>
{moment(modalPost.createdAt).fromNow()}
</span>
</h2>
<span className="data-icon" onClick={() => setModal(false)}>
<GrClose />
</span>
</div>
<div className="message">
<h2>{modalPost.title}</h2>
<p>{modalPost.message}</p>
</div>
</div>
</div>
</div>
</div>
)} */}
{/* */}
{posts.map(post => {
const { _id, title, message, image, createdAt, likes } = post;
return (
<div className="Posts-container" key={_id}>
<div className="Fit">
<div className="Fit-stuff">
<h2 className="Fit-stuff_title">
User <br />{" "}
<span style={{ fontWeight: "400" }}>
{moment(createdAt).fromNow()}
</span>
</h2>
<a
className="Fit-stuff_edit"
href="#form"
onClick={() => setCurrentId(_id)}
>
<BiDotsVertical />
</a>
</div>
<div className="Fit-data">
<h2 className="Fit-data_title">{title}</h2>
<p className="Fit-data_message">{message}</p>
{image ? (
<div className="Fit-img">
<img
onClick={() => ModalWindow(post)}
src={image}
alt=""
/>
</div>
) : (
<div></div>
)}
</div>
<div className="Fit-shit">
<span>
{animation ? (
<AiFillLike className="fullLightBlue" />
) : (
<BiLike />
)}
{likes}
</span>
<span onClick={() => dispatch(deletePost(_id))}>
<MdDeleteSweep />
</span>
</div>
</div>
</div>
);
})}
</div>
);
}
};
export default Posts;
The form where i call update and create Post
import React, { useState, useEffect } from "react";
import Filebase from "react-file-base64";
// For the actions
import { useDispatch, useSelector } from "react-redux";
import { createPost, updatePost } from "../actions/posts.js";
import {
Wrapper,
FormContainer,
Data,
DataInput,
SecondDataInput,
FormContainerImg,
FormContainerButtons,
Buttons
} from "./FormStyled.js";
const Form = ({ currentId, setCurrentId }) => {
const [formData, setFormData] = useState({
title: "",
message: "",
image: ""
});
const specificPost = useSelector(state =>
currentId ? state.posts.find(p => p._id === currentId) : null
);
// Sending The Data And Editing The data
const dispatch = useDispatch();
useEffect(() => {
if (specificPost) setFormData(specificPost);
}, [specificPost]);
// Clear Inputs
const clear = () => {
setCurrentId(0);
setFormData({ title: "", message: "", image: "" });
};
const handleSubmit = async e => {
e.preventDefault();
if (currentId === 0) {
dispatch(createPost(formData));
clear();
} else {
dispatch(updatePost(currentId, formData));
clear();
}
};
return (
<Wrapper>
<FormContainer onSubmit={handleSubmit}>
<Data>
<DataInput
name="title"
maxLength="50"
placeholder="Title"
type="text"
value={formData.title}
onChange={e => setFormData({ ...formData, title: e.target.value })}
/>
<SecondDataInput
name="message"
placeholder="Message"
maxLength="300"
value={formData.message}
required
onChange={e =>
setFormData({ ...formData, message: e.target.value })
}
/>
<FormContainerImg>
<Filebase
required
type="file"
multiple={false}
onDone={({ base64 }) =>
setFormData({ ...formData, image: base64 })
}
/>
</FormContainerImg>
<FormContainerButtons>
<Buttons type="submit" create>
{specificPost ? "Edit" : "Create"}
</Buttons>
<Buttons onClick={clear} clear>
Clear
</Buttons>
</FormContainerButtons>
</Data>
</FormContainer>
</Wrapper>
);
};
export default Form;
My actions
import {
GETPOSTS,
CREATEPOST,
DELETEPOST,
UPDATEPOST,
LIKEPOST
} from "../actionTypes/posts.js";
import * as api from "../api/posts.js";
export const getPosts = () => async dispatch => {
try {
const { data } = await api.getPosts();
dispatch({ type: GETPOSTS, payload: data });
} catch (error) {
console.log(error);
}
};
export const createPost = newPost => async dispatch => {
try {
const { data } = await api.createPost(newPost);
dispatch({ type: CREATEPOST, payload: data });
} catch (error) {
console.log(error);
}
};
export const updatePost = (id, updatePost) => async dispatch => {
try {
const { data } = await api.updatePost(id, updatePost);
dispatch({ type: UPDATEPOST, payload: data });
} catch (error) {
console.log(error);
}
};
export const deletePost = id => async dispatch => {
try {
await api.deletePost(id);
dispatch({ type: DELETEPOST, payload: id });
} catch (error) {
console.log(error);
}
};
Redux Part
import {
GETPOSTS,
CREATEPOST,
DELETEPOST,
UPDATEPOST,
LIKEPOST
} from "../actionTypes/posts.js";
const postData = (posts = [], action) => {
switch (action.type) {
case GETPOSTS:
return action.payload;
case CREATEPOST:
return [...posts, action.payload];
case UPDATEPOST:
return posts.map(post =>
action.payload._id === post._id ? action.payload : posts
);
case DELETEPOST:
return posts.filter(post => post._id !== action.payload);
default:
return posts;
}
};
export default postData;
My controllers in the backend
import mongoose from "mongoose";
import infoPost from "../models/posts.js";
// Getting All The Posts
export const getPosts = async (req, res) => {
try {
const Posts = await infoPost.find();
res.status(200).json(Posts);
} catch (error) {
res.status(404).json({ message: error.message });
console.log(error);
}
};
// Creating A Post
export const createPost = async (req, res) => {
const { title, message, image } = req.body;
const newPost = new infoPost({ title, message, image });
try {
await newPost.save();
res.status(201).json(newPost);
} catch (error) {
res.status(409).json({ message: error.message });
console.log(error);
}
};
// Update A Post
export const updatePost = async (req, res) => {
const { id } = req.params;
const { title, message, image } = req.body;
if (!mongoose.Types.ObjectId.isValid(id))
return res.status(404).send(`No Post With Id Of ${id}`);
const updatedPost = { title, message, image, _id: id };
await infoPost.findByIdAndUpdate(id, updatedPost, { new: true });
res.json(updatedPost);
};
// Deleting A Post
export const deletePost = async (req, res) => {
const { id } = req.params;
if (!mongoose.Types.ObjectId.isValid(id))
return res
.status(404)
.send(`We Couldnt Found The Post With Id Of ${id} To Delete`);
await infoPost.findByIdAndRemove(id);
res.json(`Post With Id Of ${id} Deleted Succesfully`);
};
// Liking A Post
export const likePost = async (req, res) => {
const { id } = req.params;
if (!mongoose.Types.ObjectId.isValid(id))
return res.status(404).send(`No post with id: ${id}`);
const post = await infoPost.findById(id);
const updatedPost = await infoPost.findByIdAndUpdate(
id,
{ likeCount: post.likeCount + 1 },
{ new: true }
);
res.json(updatedPost);
};
Even though i've been trying to solve this problem for nearly 3.5 hours, i think that the problem might be in my Posts.js part, if you can help me, you're the greatest !

post method from API express & angular 10

I'm trying to do a post method with angular and express.js to do that I created a file called index.js where I added different method but in my front end in Angular I would like to simply add data, how to do with reactive forms ?
I followed several tutorials but I did my best
thank you.
index.js
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.urlencoded({ extended: true }));
const parkings = require('../parkings.json');
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
app.use(express.json());
// Get all parkings details
app.get('/parkings', (req, res) => {
res.status(200).json(parkings)
});
// Get parkings by id
app.get('/parkings/:id', (req, res) => {
const id = parseInt(req.params.id)
const parking = parkings.find(parking => parking.id === id)
res.status(200).json(parking)
});
// post
app.post('/parkings', (req, res) => {
parkings.push(req.body)
res.status(200).json(parkings)
})
app.listen(3000, () => {
console.log("Listening to port 3000");
})
service
url: string = ('http://localhost:3000');
parkingForm = new FormGroup({
name: new FormControl(),
type: new FormControl(),
city: new FormControl()
});
array: any [];
constructor(private http: HttpClient) { }
get(): Observable<any> {
return this.http.get<any>(`${this.url}/parkings`);
}
postMethod() {
let myFormData = new FormData();
myFormData.append('name', this.parkingForm.value.name);
myFormData.append('type', this.parkingForm.value.type);
myFormData.append('city', this.parkingForm.value.city);
return this.http.post(this.url, myFormData,
{ responseType: 'text' }).subscribe(
(response) => this.array.push(response),
(error) => console.log(error)
);
}
ts.file
export class AppComponent implements OnInit {
getTab: any = [];
constructor(private parkingsService: ParkingsService) {}
ngOnInit() {
this.parkingsService.get().subscribe(data => {
this.getTab = data;
})
};
add() {
this.parkingsService.postMethod();
}
}
html
<table>
<tr>
<th>name</th>
<th>type</th>
<th>ville</th>
</tr>
<tr *ngFor="let parking of getTab">
<td>{{parking.name}}</td>
<td>{{parking.type}}</td>
<td>{{parking.city}}</td>
</tr>
</table>
<form [formGroup]="parkingForm">
<div class="form-group">
<input type="text" placeholder="enter name" name="name" formControlName="name"><br>
<input type="text" placeholder="enter type" name="type" formControlName="type"><br>
<input type="text" placeholder="enter city" name="city" formControlName="city"><br>
<button (click)="add()">Ajouter</button>
</div>
</form>
parkingForm: FormGroup;
this.parkingForm = this.formBuilder.group({
name: ['', [Validators.required]],
type: ['', [Validators.required]],
city: ['', [Validators.required]]
});
constructor(private formBuilder: FormBuilder) { }
ngOnInit(){
}
add() {
let bodyJSON={
name:this.parkingForm.get('name').value,
type:this.parkingForm.get('type').value,
city:this.parkingForm.get('city').value
}
this.parkingsService.postMethod(bodyJSON);
}
postMethod(data) {
let myFormData = new FormData();
myFormData.append('name', data.name);
myFormData.append('type', data.type);
myFormData.append('city', data.city);
return this.http.post(this.url, myFormData,
{ responseType: 'text' }).subscribe(
(response) => this.array.push(response),
(error) => console.log(error)
);
}

How do I use data from POST request for the next GET request

I'm trying to build a web app that uses Spotify API now. I want it to send a search keyword that an user submits to the server and send back its search result to the front end. The problem is I get a 404 status code for the fetch call. The POST request works fine.
Main.js
import React, { Component } from "react";
import SingerCard from "./SingerCard";
import axios from "axios";
export class Main extends Component {
constructor(props) {
super(props);
this.state = {
keyword: "",
artists: [],
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({ keyword: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
axios
.post(
"http://localhost:4000/search_result",
{
keyword: this.state.keyword,
},
{
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
}
)
.then(function (res) {
console.log(res);
})
.catch(function (err) {
console.log(err);
});
}
componentDidMount() {
fetch("http://localhost:4000/api")
.then((res) => res.json)
.then((artists) => {
this.setState({ artists });
});
}
render() {
return (
<div className="main">
<form onSubmit={this.handleSubmit}>
<label htmlFor="search">Search an artist: </label>
<span>
<input
type="search"
value={this.state.keyword}
onChange={this.handleChange}
name="keyword"
/>
<button type="submit" value="Submit">
Search
</button>
</span>
</form>
<br />
<div className="container">
{this.state.artists.map((elem) => (
<SingerCard
images={elem.images}
name={elem.name}
artists={this.state.artists}
/>
))}
{console.log(this.state.artists)}
</div>
<br />
</div>
);
}
}
export default Main;
server.js
const express = require("express");
const SpotifyWebApi = require("spotify-web-api-node");
const bodyParser = require("body-parser");
const cors = require("cors");
const app = express();
const port = 4000 || process.env.PORT;
require("dotenv").config();
app.use(express.json());
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
// Create the api object with the credentials
var spotifyApi = new SpotifyWebApi({
clientId: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
});
// Retrieve an access token.
spotifyApi.clientCredentialsGrant().then(
function (data) {
console.log("The access token expires in " + data.body["expires_in"]);
console.log("The access token is " + data.body["access_token"]);
// Save the access token so that it's used in future calls
spotifyApi.setAccessToken(data.body["access_token"]);
},
function (err) {
console.log("Something went wrong when retrieving an access token", err);
}
);
app.post("/search_result", (req, res) => {
console.log(req.body.keyword);
spotifyApi.searchArtists(req.body.keyword).then(function (data) {
var search_res = data.body.artists.items;
res.json(search_res);
app.get("http://localhost:/api", (req, res) => {
res.json(search_res);
res.end();
});
res.end();
}),
function (err) {
console.log(err);
};
});
app.listen(port, () => console.log(`It's running on port ${port}`));
I think the app.get() in the app.post() causes the error but I can't figure out another way to send the search result back.
You're getting a 404 because the get method is not correctly defined.
Update your server code to define the get method to just keep the pathname, like this:
app.get("/api", (req, res) => {
// ...
}
Currently, you are defining this route inside the app.post. The get route definition should be outside of the post route.
Use Axios.get
import React, { Component } from "react";
// import SingerCard from "./SingerCard";
import axios from "axios";
export class Main extends Component {
constructor(props) {
super(props);
this.state = {
keyword: "",
artists: []
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({ keyword: e.target.value });
}
handleSubmit(e) {
e.preventDefault();
const headers = {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*"
};
axios.post(
"https://jsonplaceholder.typicode.com/users",
{ keyword: this.state.keyword },
{ headers: headers }
)
.then(res => {
console.log(res.data);
})
.catch(err => {
console.log(err);
});
}
componentDidMount() {
axios.get("https://jsonplaceholder.typicode.com/users").then(res => {
this.setState({
artists: res.data
});
});
}
render() {
return (
<div className="main">
<form onSubmit={this.handleSubmit}>
<label htmlFor="search">Search an artist: </label>
<span>
<input
type="search"
value={this.state.keyword}
onChange={this.handleChange}
name="keyword"
/>
<button type="submit" value="Submit">
Search
</button>
</span>
</form>
<br />
<div className="container">
{this.state.artists.map(elem => (
<div key={elem.id}>
<ul>
<li>{elem.name}</li>
</ul>
</div>
))}
</div>
</div>
);
}
}
export default Main;

How to fix "Can't perform a React state update on an unmounted component"?

I'm building a TODO list and one of the things that it needs to do is delete.
Here is my server.js code
const app = express();
const bodyParser = require('body-parser');
const cors = require('cors');
const mongoose = require('mongoose');
const cpdRoutes = express.Router();
const PORT = 4000;
let Cpd = require("./cpd.model");
app.use(cors());
app.use(bodyParser.json());
//connects my backend to my mongo database
mongoose.connect('mongodb://127.0.0.1:27017/cpds', { useNewUrlParser: true });
const connection = mongoose.connection;
connection.once('open', function() {
console.log("MongoDB database connection established successfully");
})
cpdRoutes.route('/').get(function(req, res) {
Cpd.find(function(err, cpds) {
if (err) {
console.log(err);
}
else {
res.json(cpds);
}
});
});
//finds the data by id
cpdRoutes.route('/:id').get(function(req, res) {
let id = req.params.id;
Cpd.findById(id, function(err, cpd) {
res.json(cpd);
});
});
//creating data
cpdRoutes.route('/add').post(function(req, res) {
let cpd = new Cpd(req.body);
cpd.save()
.then(cpd => {
res.status(200).json({'cpd': 'New data added successfully'});
})
.catch(err => {
res.status(400).send('Adding new data failed');
});
});
//update data
cpdRoutes.route('/update/:id').post(function(req, res) {
Cpd.findById(req.params.id, function(err, cpd) {
if (!cpd)
res.status(404).send("data is not found");
else
cpd.cpd_date = req.body.cpd_date;
cpd.cpd_activity = req.body.cpd_activity;
cpd.cpd_hours = req.body.cpd_hours;
cpd.cpd_learningStatement = req.body.cpd_learningStatement;
cpd.save().then(cpd => {
res.json('Data updated!');
})
.catch(err => {
res.status(400).send("Update not possible");
});
});
});
// cpdRoutes.route('/delete/:id').post(function(req, res) {
// Cpd.findById(req.params.id, function(err, cpd) {
// if (!cpd)
// res.status(404).send("data is not found");
// else
// cpd.cpd_date = req.body.cpd_date;
// cpd.cpd_activity = req.body.cpd_activity;
// cpd.cpd_hours = req.body.cpd_hours;
// cpd.cpd_learningStatement = req.body.cpd_learningStatement;
// cpd.save().then(cpd => {
// res.json('Data updated!');
// })
// .catch(err => {
// res.status(400).send("Update not possible");
// });
// });
// });
cpdRoutes.route.get('/delete', function(req, res){
var id = req.query.id;
Cpd.find({_id: id}).remove().exec(function(err, expense) {
if(err)
res.send(err)
res.send('Data successfully deleted!');
})
});
app.use('/cpds', cpdRoutes);
app.listen(PORT, function() {
console.log("Server is running on Port: " + PORT);
});
My delete component:
import React from 'react';
import axios from 'axios';
import { Button } from 'react-bootstrap';
import { Link } from 'react-router-dom';
class DeleteCpd extends React.Component {
constructor(){
super();
this.state={id:''};
this.onClick = this.onClick.bind(this);
this.delete = this.delete.bind(this);
}
// componentDidMount() {
// this.setState({
// id: this.props.cpds.id
// })
// }
componentDidMount() {
axios.get('http://localhost:4000/cpds/'+this.props.match.params.id)
.then(response => {
this.setState({
cpd_date: response.data.cpd_date,
cpd_activity: response.data.cpd_activity,
cpd_hours: response.data.cpd_hours,
cpd_learningStatement: response.data.cpd_learningStatement
})
})
.catch(function (error) {
console.log(error);
})
}
onClick(e){
this.delete(this);
}
delete(e){
axios.get('http://localhost:4000/cpds/'+this.props.match.params.id)
.then(function(response) {
});
}
render(){
return (
<Button onClick={this.onClick}>
<Link to={{pathname: '/', search: '' }} style={{ textDecoration: 'none' }}>
<span className="glyphicon glyphicon-remove"></span>
</Link>
</Button>
)
}
}
export default DeleteCpd;
and my App.js:
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import "bootstrap/dist/css/bootstrap.min.css";
import CreateCpd from "./components/create-cpd.component";
import EditCpd from "./components/edit-cpd.component";
import CpdsList from "./components/cpds-list.component";
import DeleteCpd from "./components/cpds-delete.component";
class App extends Component {
render() {
return (
<Router>
<div className="container">
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<Link to="/" className="navbar-brand">MERN-Stack Cpd tracker App</Link>
<div className="collpase navbar-collapse">
<ul className="navbar-nav mr-auto">
<li className="navbar-item">
<Link to="/" className="nav-link">Data List</Link>
</li>
<li className="navbar-item">
<Link to="/create" className="nav-link">Create Cpd data</Link>
</li>
</ul>
</div>
</nav>
<br/>
<Route path="/" exact component={CpdsList} />
<Route path="/edit/:id" component={EditCpd} />
<Route path="/delete/:id" component={DeleteCpd} />
<Route path="/create" component={CreateCpd} />
</div>
</Router>
);
}
}
export default App;
This is the error my getting:
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
in CpdList (created by Context.Consumer)
What I'm trying to do is delete via id. What am I doing wrong?
This is my CPDList:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';
// import { CSVLink } from "react-csv";
// import DeleteCpd from './cpd_delete.component';
const Cpd = props => (
<tr>
<td>{props.cpd.cpd_date}</td>
<td>{props.cpd.cpd_activity}</td>
<td>{props.cpd.cpd_hours}</td>
<td>{props.cpd.cpd_learningStatement}</td>
<td>{props.cpd.cpd_evidence}</td>
<td>
<Link to={"/edit/"+props.cpd._id}>Edit</Link>
</td>
<td>
<Link to={"/delete/"+props.cpd._id}>Delete(not working yet)</Link>
</td>
</tr>
)
export default class CpdList extends Component {
constructor(props) {
super(props);
this.state = {
cpds: [],
// csvData:[
// {
// "date": ""
// },
// {
// "activity": ""
// },
// {
// "hours": ""
// },
// {
// "learningStatement": ""
// },
// {
// "evidence": ""
// }
// ]
};
};
// exportCsv()
// {
// var csvRow=[];
// }
componentDidMount() {
axios.get('http://localhost:4000/cpds/')
.then(response => {
this.setState({ cpds: response.data });
})
.catch(function (error){
console.log(error);
});
};
componentDidUpdate() {
axios.get('http://localhost:4000/cpds/')
.then(response => {
this.setState({ cpds: response.data });
})
.catch(function (error){
console.log(error);
});
}
cpdList() {
return this.state.cpds.map(function(currentCpd, i){
return <Cpd cpd={currentCpd} key={i} />;
});
}
render() {
return(
<div>
<h3>Cpd Data List</h3>
<table className="table table-striped" style={{ marginTop: 20 }} >
<thead>
<tr>
<th>Date</th>
<th>Activity</th>
<th>Hours</th>
<th>Learning Statement</th>
<th>Evidence</th>
</tr>
</thead>
<tbody>
{ this.cpdList() }
</tbody>
</table>
{/* <CSVLink data={csvData}
filename={"db.csv"}
color="primary"
style={{float: "left", marginRight: "10px"}}
className="btn btn-primary"
>Download .CSV
</CSVLink> */}
</div>
)
}
};
please ignore the commented out code still working on that.

Angular2 API call return nothing

My problem is, that it isn't displayed in html form. How can I solve this ?
The query is well, and I get the result on URL, but can't display it on component.html.
( It works and I see if I call the URL /api/mainstorage so it display me the JSON content.)
Index.js
var express = require('express');
var router = express.Router();
// http://localhost:3000/
router.get('/', function(req, res, next) {
res.status(200)
.json({
status: 'success',
message: 'Live long and prosper!'
});
});
var db = require('./queries');
router.get('/api/mainstorage', db.getAllDocuments);
module.exports = router;
Queries.js
var promise = require('bluebird');
var options = {
// Initialization Options
promiseLib: promise
};
var pgp = require('pg-promise')(options);
var connectionString ='postgres://dbuser:Storage#localhost/mainstorage'
var db = pgp(connectionString);
const axios = require('axios');
const API = 'http://localhost:3000';
function getAllDocuments(req, res, next) {
axios.get(`${API}/main`)
db.any('SELECT * FROM files')
.then(function (data) {
res.status(200)
.json({
status: 'success',
data: data,
message: 'Retrieved all files'
});
})
.then(documents => {
res.send(200).json();
})
.catch(function (err) {
return next(err);
});
}
module.exports = {
getAllDocuments: getAllDocuments
};
documents.component.ts
export class DocumentsComponent implements OnInit {
title = 'app works!';
mainstorage;
documents: any [];
constructor(private documentsService: DocumentsService) { }
ngOnInit() {
// Retrieve documents from the API
this.documentsService.getAllDocuments().subscribe(documents => {
this.documents = documents;
});
}
}
documents.service.ts
#Injectable()
export class DocumentsService {
constructor(private http: Http) {}
getAllDocuments(){
return this.http.get('/api/mainstorage')
.map(res => res.json());
}
}
documents.component.html
<div class="row" *ngFor="let document of documents">
<div class="card card-block">
<h4 class="card-title">{{ documents.id }}</h4>
<p class="card-text">{{document.country}}</p>
You are not able to see anything in the html because service data is asynchronous and you are trying to display it before the service returns it back.
You can solve this by wrapping your variables in *ngIf
<div *ngIf='documnets'>
<div class="row" *ngFor="let document of documents">
<div class="card card-block">
<h4 class="card-title">{{ documents.id }}</h4>
<p class="card-text">{{document.country}}</p>
</div>
</div>
</div>
*ngIf will check if there are documents and once data from service is received it will be displayed.

Resources