Get data from Node REST API and populate other controls - node.js

After login in React Web app, I am going to show profile detail to user and I am fetching profile detail from NODE REST API. I am not sure how to do that. I think the problem is in the render section, because if I don't use the render section then it is showing me some data.
export class AccountDetails extends Component {
constructor (props) {
super(props)
this.state = {
userDetail:null
}
this.callAPI()
}
async callAPI() {
await fetch("http://localhost:5000/customers?email="+JSON.parse(localStorage.getItem('email'))
.then(res=>res.json())
.then(res=>this.setState({userDetail:res}));
console.log(this.state.userDetail);
}
this is my render section
<tr>
<td className="text-left">First Name : </td>
<td className="text-left">{this.userDetail.firstName}</td>
</tr>
I am getting null in console.log
If I don't use {this.userDetail.firstName} then I am getting
0:
email: "manu#gmail.com"
firstName: "Manpreet"
lastName: "Narang"
occupants: 2
phone: 12345
__proto__: Object
length: 1
__proto__: Array(0)

Since you're using classes you need to make your fetch in componentDidMount like so:
constructor (props) {
super(props)
this.state = {
userDetail: null,
isLoaded: false // Notice this new property and check the render method below
}
}
componentDidMount() {
fetch("http://localhost:5000/customers?email="+JSON.parse(localStorage.getItem('email'))
.then(res => res.json())
.then(res => this.setState({ userDetail: res, isLoaded: true }));
}
Only then will the setState work and rerender your component.
Then, in your render method:
render() {
if(!isLoaded) return <p>Loading...</p>
return (
<tr>
<td className="text-left">First Name : </td>
<td className="text-left">{this.userDetail.firstName}</td>
</tr>
)
}
Reference: https://reactjs.org/docs/react-component.html#componentdidmount

Related

React: Cannot read properties of undefined (reading '0')

i am getting the error
Grade.jsx:52 Uncaught TypeError: Cannot read properties of undefined (reading '0')
at Grade.jsx:52:1
at Array.map (<anonymous>)
at Grade (Grade.jsx:39:1)
at renderWithHooks (react-dom.development.js:16305:1)
at mountIndeterminateComponent (react-dom.development.js:20074:1)
at beginWork (react-dom.development.js:21587:1)
at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1)
at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1)
at invokeGuardedCallback (react-dom.development.js:4277:1)
at beginWork$1 (react-dom.development.js:27451:1)
(anonymous) # Grade.jsx:52
Grade # Grade.jsx:39
renderWithHooks # react-dom.development.js:16305
mountIndeterminateComponent # react-dom.development.js:20074
beginWork # react-dom.development.js:21587
callCallback # react-dom.development.js:4164
invokeGuardedCallbackDev # react-dom.development.js:4213
invokeGuardedCallback # react-dom.development.js:4277
beginWork$1 # react-dom.development.js:27451
performUnitOfWork # react-dom.development.js:26557
workLoopSync # react-dom.development.js:26466
renderRootSync # react-dom.development.js:26434
recoverFromConcurrentError # react-dom.development.js:25850
performSyncWorkOnRoot # react-dom.development.js:26096
flushSyncCallbacks # react-dom.development.js:12042
(anonymous) # react-dom.development.js:25651
react-dom.development.js:18687 The above error occurred in the <Grade> component:
at Grade (http://localhost:3000/static/js/bundle.js:6687:56)
at RenderedRoute (http://localhost:3000/static/js/bundle.js:277704:5)
at Outlet (http://localhost:3000/static/js/bundle.js:278056:26)
at div
at StudentProfileLayout (http://localhost:3000/static/js/bundle.js:6946:72)
at RenderedRoute (http://localhost:3000/static/js/bundle.js:277704:5)
at Routes (http://localhost:3000/static/js/bundle.js:278141:5)
at Routing
at App (http://localhost:3000/static/js/bundle.js:349:78)
at Router (http://localhost:3000/static/js/bundle.js:278079:15)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:276396:5)
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
but if i comment out the grade column value before the Grade comp renders,there will be no error.it will display all the columns with there values after that if i uncomment out it displays the grade column values properly.
but without commenting out the values of the grade column,the error happens
please i need help guys,help.
the server responds with this values
ayne abreham alemayehu
new ObjectId("63efb168503e390f0b7c986a")
new ObjectId("63efb168503e390f0b7c986a")
[
{
gd: {
_id: new ObjectId("63f16c7f03e5a86d748ab2c4"),
batch: 1,
department: 'None',
stream: 'None',
subject: 'b',
class: new ObjectId("63efb168503e390f0b7c986a"),
grades: [Array],
createdAt: 2023-02-19T00:25:35.272Z,
updatedAt: 2023-02-19T00:25:35.272Z,
__v: 0
},
sem: 1
},
{
gd: {
_id: new ObjectId("63f16c8903e5a86d748ab2c9"),
batch: 1,
department: 'None',
stream: 'None',
subject: 'd',
class: new ObjectId("63efb168503e390f0b7c986a"),
grades: [Array],
createdAt: 2023-02-19T00:25:45.106Z,
updatedAt: 2023-02-19T00:25:45.106Z,
__v: 0
},
sem: 1
sem: 1
}
sem: 1
}
]
the route
router.route("/find/grades").post(async (req, res) => {
try {
const { fullName } = req.body;
const user = await User.findOne({ fullName });
console.log(fullName);
const grades = await Grade.find({
department: user.department,
stream: user.stream,
batch: user.batch,
"grades.studentId": user._id,
});
const updatedGrades = await Promise.all(
grades.map(async (gd, i) => {
console.log(gd.class);
const sem = await Class.findById({ _id: gd.class });
return { gd, sem: sem.semester };
})
);
console.log(updatedGrades);
res.json({ updatedGrades });
} catch (err) {
console.log(err);
}
});
Grade.jsx
import { useState, useEffect, useContext } from "react";
import axios from "axios";
import { UserContext } from "../App.jsx";
function Grade() {
const { state, dispatch } = useContext(UserContext);
const [data, setData] = useState([{ gd: {}, sem: 1 }]);
useEffect(() => {
const fetchData = async () => {
try {
const res = await axios.post("http://localhost:5000/user/find/grades", {
fullName: state.name,
});
const newData = res.data.updatedGrades.map((item) => ({ gd: item.gd, sem: item.sem }));
console.log(newData);
setData(newData);
} catch (err) {
console.log(err);
}
};
fetchData();
}, []);
console.log(data);
return (
<div className="w-full text-center">
{console.log(data)}
<table className="table-auto lg:table-fixed w-full">
<thead>
<tr className="bg-gray-800 text-white">
<th className="lg:w-52 px-4 py-2">Batch</th>
<th className="px-4 py-2">Department</th>
<th className="px-4 py-2">Stream</th>
<th className="px-4 py-2">Semester</th>
<th className="px-4 py-2">Subject</th>
<th className="px-4 py-2">Grade</th>
</tr>
</thead>
<tbody>
{data && data.length > 0 &&
data.map((item, index) => (
<tr key={index} className="text-gray-700">
<td className="border px-2 py-px">{item.gd.batch}</td>
<td className="text-center border px-0.5 py-px">
{item.gd.department}
</td>
<td className="border px-1.5 py-px">{item.gd.stream}</td>
<td className="border px-2 py-px">{item.sem}</td>
<td className="text-center border px-2 py-px">
{item.gd.subject}
</td>
<td className="text-center border px-2 py-px">
{item.gd?.grades[0]?.grade}
</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default Grade;
Can you, please, console log item.gd.grades? I have a feeling that that will be an Array of Arrays, meaning it's not [{ grade: 5 }] but [[{ grade: 5 }]] (note that it is a nested array).
If that would be an array of objects you would see [Object] not [Array]. To see the full log you can do the following: console.log(JSON.stringify(thingie, null, 2)) (where thingie is what you want to log, null is the replacer, 2 - indent, refer to MDN JSON.stringify)

How do we load the selected Item values from MongoDB for <Select /> in react

I am new to learning React. I have build a small application which includes React,Node and MongoDB. I have two modules here, the Create data and the Edit data. My question is regarding the Select component from Reacts's built in library. When I create a user, I enter his availability time slots(isMulti in Select) from a component. On Submit, this data along with the the slots is getting inserted in the Mongo Db.This is all fine. I am having problem when loading the page for edit. How to make the previously selected items from dropdown show up on page load. The other fields show up fine with componentDidMount().
Here is what my update module looks like-
// eslint-disable-next-line
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import Select from 'react-select';
import DatePicker from 'react-datepicker';
import "react-datepicker/dist/react-datepicker.css";
// Connecting from front end to backend with Axios
import axios from "axios";
export default class EditPanel extends Component {
constructor(props) {
super(props);
//defining this
this.onChangefield1 = this.onChangefield1.bind(this);
this.onChangefield2 = this.onChangefield2.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.handleChange=this.handleChange.bind(this);
this.state = {
field1: "",
field2: "",
timeSlots:[],
filterOptions:[
{ label:"9:00am to 10:00am", value: "9:00am to 10:00am" },
{ label: "10:00am to 11:00am", value: "10:00am to 11:00am" },
{ label: "11:00am to 12:00pm", value: "11:00am to 12:00pm" },
{ label: "12:00pm to 01:00pm", value: "12:00pm to 01:00pm" },
{ label: "01:00pm to 02:00pm", value: "01:00pm to 02:00pm" },
],
selectedOption:[]
}
}
componentDidMount() {
console.log("inside componentmount");
axios.get('http://localhost:5000/someEndpoint/' + this.props.match.params.id)
.then(response => {
this.setState({
field1: response.data.field1,
field2: response.data.field2,
mailId: response.data.mailId,
timeSlots:response.data.timeSlots,
selectedOption: response.data.timeSlots,
})
console.log("Meow"+response.data.timeSlots);
})
.catch(function (error) {
console.log(error);
})
}
onChangefield1(e) {
this.setState({ field1: e.target.value });
}
onChangefield2(e) {
this.setState({ field2: e.target.value });
}
// This is for insertion of any new selected list items
handleChange = selectedOption => {
console.log(selectedOption.value);
this.setState({ selectedOption: selectedOption.value }); // selected option value
console.log(selectedOption);
var dataArray = [];
for(var o in selectedOption) {
dataArray.push(selectedOption[o].value);
this.setState({ timeSlots: dataArray });
console.log(this.timeSlots);
}
};
onSubmit(e) {
e.preventDefault();
const panel =
{
field1: this.state.field1,
field2: this.state.field2,
timeSlots:this.state.timeSlots
}
axios.post('http://localhost:5000/someEndpoint/update/' + this.props.match.params.id, panel)
.then(res => console.log(res.data));
console.log("calling from edit");
window.location = '/';
}
render() {
return (
<div>
<h3>Edit Panel Info</h3>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Field 1: </label>
<input type="text"
required
className="form-control"
value={this.state.field1}
onChange={this.onChangefield1}
/>
</div>
<div className="form-group">
<label>field2: </label>
<input
type="text"
className="form-control"
value={this.state.field1}
onChange={this.onChangefield2}
/>
</div>
<div className="form-group">
<label>Time Slots</label>
<div>
<Select
options={this.state.filterOptions} // Options to display in the dropdown
isMulti
value={this.state.selectedOption} // would like to see the values we have in DB
onChange={this.handleChange}
closeIcon="close"
/>
</div>
</div>
<div className="form-group">
<input type="submit" value="Edit Panel" className="btn btn-primary" />
</div>
</form>
</div>
)
enter code here
}
}`enter image description here`
[enter image description here][1]
[1]: https://i.stack.imgur.com/NliEH.png
The mongo db data looks like
timeSlots
:
Array
0
:
"10:00am to 11:00am"
1
:
"12:00pm to 01:00pm"

Error: values.map is not a function ( why I get this error )

i am fetching details from database through Id wanted to display that into the table, but for initial purpose i wanted to just display on browser without table and stuff.. am getting values.map is not a function but when I did console.log(values), got {title: "", description: "", tags: "", photo: "", loading: false, …}
createdBlog: ""
description: ""
error: ""
formData: ""
getaRedirect: false
loading: false
photo: ""
tags: ""
title: ""
proto: Object
what to do, please help
import React, { useState, useEffect } from "react";
import "../../styles.css";
import { getoneBlog } from "../helper/coreapicalls";
import ImageHelper from "../helper/ImageHelper";
const Fullblog = ({ match }) => {
const [values, setValues] = useState({
title: "",
description: "",
tags: "",
photo: "",
loading: false,
error: "",
createdBlog: "",
getaRedirect: false,
formData: "",
});
const {
title,
description,
tags,
loading,
error,
createdBlog,
getaRedirect,
formData,
} = values;
const preload = (blogId) => {
getoneBlog(blogId).then((data) => {
//console.log(data);
if (data.error) {
setValues({ ...values, error: data.error });
} else {
// preloadCategories();
setValues({
...values,
title: data.title,
description: data.description,
tags: data.tags,
formData: new FormData(),
});
}
});
};
console.log(values);
useEffect(() => {
preload(match.params.blogId);
}, []);
return (
<div>
<div className="py-md-5 py-3">
<div className="Fullblog ">
{values.map((fullblog, index) => {
return (
<div>
<h1 className="FullblogTittle">
Founder Leandra Medine Cohen announced the news to her
employees on a Zoom call earlier this week.
{fullblog.title}
</h1>
<p className="tags">tags </p>
<img
src="https://cdn.pixabay.com/photo/2020/10/17/17/41/girl-5662873_960_720.jpg"
className="FullblogImg"
alt="img"
/>
<ImageHelper />
<p className="description">
CULTURE How to Celebrate Halloween at Home This Year From
horror movie marathons to Halloween-themed drive-in features
to virtual pumpkin carving parties, here's how to celebrate
Halloween safely this year. By Pahull Bains Date October 22,
2020 With cases on the rise in certain regions of Ontario ’s A
Little Blurry. The livestream will be viewable on demand for
24 hours for ticket holders. Get your tickets here.
</p>
</div>
);
})}
</div>
</div>
</div>
);
};
export default Fullblog;
coreapicalls code-
// get all Blogs
export const getBlogs = () => {
return fetch(`${API}/blogs`, {
method: "GET",
})
.then((response) => {
return response.json();
})
.catch((err) => console.log(err));
};
//get a Blog
export const getoneBlog = (blogId) => {
return fetch(`${API}blog/${blogId}`, {
method: "GET",
})
.then((response) => {
return response.json();
})
.catch((err) => console.log(err));
};
You can use .map() function on an Array but your state looks to be set up as an Object rather than an array.
Check these lines:
{values.map((fullblog, index) => {
&
const [values, setValues] = useState({ ... }); // This is an object
Reference
The map() method creates a new array populated with the results of
calling a provided function on every element in the calling array.
So the issue is, you are trying the map() on an object that's why it is showing you the error.
You can only use .map() on Array variables, as mentioned before.
You can simply do this:
Object.keys(values), which will make an Array with the keys of your object.
Object.keys(values).map( keys => console.log(values[key]) )
You used object destructuring on values but there is no such method as Object.prototype.map...
You can loop over Object.values(values) with map or Object.keys(values) if you want to loop over the keys.
Code:
Object.values(values).map((fullblog, index) => {
// insert code here
});

Get Data from NodeJs to Angular

I want to get some data from nodejs to angular and list it on a web page.
I tried to do it but i get no answer (the web page is blank, no errors)
this is the post.model:
export interface Post {
id: string;
token: string;
lat: String;
lng: String;
}
The JSON I'm working on (from database):
{
"location": [
{
"_id": "5f3429f9fe89ef3658c5ec17",
"lat": "44.4363255",
"lng": "25.9912393",
"token": "edb153fb9d8d5628",
"__v": 0
},
{
"_id": "5f342fbadae3a42884852505",
"lat": "44.4363228",
"lng": "25.9912314",
"token": "c30af1934c22f4eb",
"__v": 0
}
]
}
post-list.component:
export class PostListComponent implements OnInit, OnDestroy {
posts: Post[] = [];
private postsSub: Subscription;
constructor(public postsService: PostsService) {
//dependency-injection
}
ngOnInit() {
this.postsService.getPosts();
this.postsSub = this.postsService
.getPostUpdateListener()
.subscribe((posts: Post[]) => {
this.posts = posts;
});
}
onShow() {
console.log('TODO');
}
ngOnDestroy() {
this.postsSub.unsubscribe();
}
post-list.component.html:
<mat-accordion multi="true" *ngIf="posts.length > 0">
<mat-expansion-panel *ngFor="let post of posts">
<mat-expansion-panel-header>
{{ post.token }}
</mat-expansion-panel-header>
<p>{{ post.lat }}</p>
<p>{{ post.lng }}</p>
<mat-action-row>
<button mat-raised-button color="accent" (click)="onShow(post.id)">
SHOW
</button>
</mat-action-row>
</mat-expansion-panel>
</mat-accordion>
<p class="info-text mat-body-1" *ngIf="posts.length <= 0">No posts added yet</p>
and also the post.service:
export class PostsService {
private posts: Post[] = [];
private postsUpdated = new Subject<Post[]>();
constructor(private http: HttpClient) {}
getPosts() {
this.http
.get<{ posts: any[] }>('127.0.0.1:8000/location')
.pipe(
map((postData) => {
return postData.posts.map((post) => {
return {
id: post._id,
token: post.token,
lat: post.lat,
lng: post.lng,
};
});
})
)
.subscribe((transformedPosts) => {
this.posts = transformedPosts;
this.postsUpdated.next([...this.posts]);
});
}
getPostUpdateListener() {
return this.postsUpdated.asObservable();
}
Basically I'm retrieving some data from a android app and save it on a mongodb database using nodejs.
The next step of my project is to list the data from the database on a web page.
I tried to get the data via getPosts() method (see post.service), then list it. As I told you, nothing shows on the web page.
the app.component.html is simple, I just called an to show a map (I will show some coords on a map later) and the , which should show the data from the database.
If i delete the <app-post-list></app-post-list>, the webpage displays a google map, so the rest of the code is working, but when i add <app-post-list></app-post-list>, it doesn't show anything anymore.
Any ideas, please?
---Edit
I resolved the "nothing appearing issue".
Now, the data can't be displayed: No posts added yet
this is the developer console log:
From your last comment, i think you just forgot to import HttpClientModule in your AppModule.
Make sure to add schema "http://" to your target url, like this:
.get<{ posts: any[] }>('http://127.0.0.1:8000/location')
If you don't do so, Angular will just interpret it as http://localhost:4200/127.0.0.1/location

Handlebars: Access has been denied to resolve the property "name" because it is not an "own property" of its parent

I got the issue with handlebars 4.7.3. I already checked the solution from this ask,
Handlebars: Access has been denied to resolve the property "from" because it is not an "own property" of its parent
but it was no solution for my code so I hope someone can help me.
Controller.js
submitPosts: (req, res) => {
// Check the attributs from create.handlebars for success or error message
const newPost = new Post( {
surname: req.body.surname,
name: req.body.name,
biography: req.body.biography,
profilpicture: req.body.profilpicture,
paintings: req.body.paintings,
});
// Safe new posts
newPost.save().then(post => {
console.log(post);
flash('success-message', 'new post!')
res.redirect('/admin/posts');
});
},
postModel.js
const
mongoose = require('mongoose');
const Schema = mongoose.Schema; // get props
const PostSchema = new Schema({
// define props --> required for a post
surname: {
type: String,
default: ''
},
name: {
type: String,
default: ''
},
biography: {
type: String,
default: ''
},
profilpicture: {
type: Object,
},
paintings : {
type: Object,
}
});
module.exports = mongoose.model('post', PostSchema);
index.handlebars
{{#each post}}
<tr>
<td>{{ surname }}</td>
<td>{{ name }}</td>
<td><img style="width: 100px; height:100px;" src="{{ profilpicture }}"></td>
<td>{{ biography }}</td>
<td><img style="width: 100px; height:100px;" src="{{ paintings }}"></td>
</tr>
{{/each}}
Already tried every possibility from the other ask on stack overflow, other handlebars version, change router code, ... NOTHING WORKS :(
Just had the same issue that wrecked my nerves.
Tried additional packages etc but in the end a simple command solve this.
Its the Command ".lean()"
Found more here: link to mongoose docs for lean()
my code example:
// show message page Route
router.get("/", (req, res) => {
//read all Message entries from db
Message.find()
//sort them descending by date property
.sort({ date: "desc" })
.lean()
//take these and call the rendered page and pass them as object to the page
.then(messages => {
res.render("messages/show_messages", { messages: messages });
});
});

Resources