not able to display fetched data on page ReactJS - node.js

in the code below i am fetching data from an API and want to display it on a page.
import React, { useState, useEffect } from "react";
import '../all.css';
import Axios from "axios";
const AllProduct = () => {
const [products, setProducts] = useState([]);
const fetchProducts = async () => {
const { data } = await Axios.get(
"http://localhost:8080/api/QueryAllProducts"
);
console.log(data.response);
setProducts(data.response);
console.log(products);
};
const display = () => {
return (products || []).map(product => (
<tr key={product.id}>
<th>{product.id}</th>
<th>{product.name}</th>
<th>{product.area}</th>
<th>{product.ownerName}</th>
<th>{product.cost}</th>
</tr>
) );
}
useEffect(() => {
fetchProducts();
}, []);
return (
<div>
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Area</th>
<th>Owner Name</th>
<th>Cost</th>
</tr>
</thead>
<tbody>
{display()}
</tbody>
</table>
</div>
)
}
export default AllProduct;
i did almost every method which i found on stackoverflow but still can't resolve the error. In frontend i have used ReactJS and in Backend i am using NodeJS
here is the screenshot of the error i am getting

Earlier, when one wanted to assign a default value to a variable, a common pattern was to use the logical OR operator (||):
let foo;
// foo is never assigned any value so it is still undefined
let someDummyText = foo || 'Hello!';
However, due to || being a boolean logical operator, the left hand-side operand was coerced to a boolean for the evaluation and any falsy value (0, '', NaN, null, undefined) was not returned. This behavior may cause unexpected consequences if you consider 0, '', or NaN as valid values.
I recommend change your || operator to ?? like:
(products ?? [])
because this '??' operator will conditions if you receive nullish value.
if you want to know more check it out here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator

I think the challenge you are having is from your display function. You should return a Jsx element before mapping the products and enclose the mapping function in the curly ({}) bracket so React knows you are now writing javascript. So you might want to re-write your display function like below:
const display = () => {
return (<React.Fragment>
{(products || []).map(product => (
<tr key={product.id}>
<th>{product.id}</th>
<th>{product.name}</th>
<th>{product.area}</th>
<th>{product.ownerName}</th>
<th>{product.cost}</th>
</tr>}))
</React.Fragment>
);
}
Also I think you should use <td>{product.name}</td>... to return table data and not <th>{product.name}</th>

Related

React how to pass state without rendering component

I have an issue where when I start at the root and click through the links all the states load in fine but when I got to copy and paste the URL into a new window it doesnt show, would I be right to assume its because the previous component isnt being rendered to set the state?
Hopefully someone can point me to some helpful articles or even have experienced this before?
Here is a link to a screen recording I made to better show what I mean https://youtu.be/M0390D4oJDg
CODE
import React from "react";
import { useLocation, useParams } from "react-router";
import PostBlock from "./PostBlock";
const PostList = () => {
const {thread} = useParams()
const { state: { description, title } = {} } = useLocation();
return (
<div>
<div className="m-10 flex justify-center">
<div style={{ width: "1216px" }}>
<div className="flex justify-center">
<div className="flex-1 justify-center mb-5 p-5 h-64 border border-gray-300">
<div>{title}</div>
<div>{description}</div>
</div>
</div>
<table className="min-w-full table-auto">
<thead className="justify-between">
<tr className="bg-gray-800">
<th className="px-8 py-2 text-left text-white">Posts</th>
</tr>
</thead>
<tbody className="bg-gray-200">
<PostBlock thread={thread}/>
</tbody>
</table>
</div>
</div>
</div>
);
};
export default PostList;
LINK
<Link to={{ pathname: `/thread/${thread}`, state: {title: title, description: description} }}>
URL
http://localhost:3000/thread/jxvgOKPrSiCnI2ocDxgJ
This react stuff is harder than I initially thought
Don't give up easily. It's one of the beautiful things!
Start with optional chaining.
const title = useLocation()?.state?.title;
const description = useLocation()?.state?.description;
If this is not supported, use &&:
const title = useLocation() && useLocation().state && useLocation().state.title;
const description = useLocation() && useLocation().state && useLocation().state.description;
And only when title and description is not null, render your contents.
const PostList = () => {
const { thread } = useParams();
const title = useLocation() && useLocation().state && useLocation().state.title;
const description = useLocation() && useLocation().state && useLocation().state.description;
return title && description ? <div></div> : null;
};
Now the code will not render the content until and unless both the values are set. And this will make sure your code loads without any errors.
I am a bit confused as to what your question really is, but you've got some issues with your code. Try this:
const PostList = () => {
const { thread } = useParams();
const { state: { description, title } = {} } = useLocation();
return <div></div>;
};
There is no reason to initialize useLocation() twice. You could've also initialized it into one constant and then access description and state through it.
const PostList = () => {
const { thread } = useParams();
const location = useLocation();
console.log(location.state.title, location.state.description);
return <div></div>;
};
Additionally, you can incorporate object?.property method as a failsafe if your state is empty:
console.log(location?.state?.title);
Take a look at proper useLocation usage here

How to format <td> value in angular dynamic table

am trying to format displayed value in an angular table
this is my table right now
instead of showing the link am trying to format the displayed content link
instead of https://www.udemy.com/course/amazon-alexa-101-publishing-alexa-skills-without-coding/
am trying to show [amazon alexa 101 publishing alexa skills without coding]
i have tried in nodejs
var url = require('url');
var adr ='https://www.udemy.com/course/technology-strategy-success/?couponCode=05DIwC2320';
var q = url.parse(adr, true);
var data = q.pathname.replace("/course/", '');
var output = data.replace("/", '');
console.log(output);
this is my ts file
import {Component, OnDestroy, OnInit} from '#angular/core';
import {ApiService} from '../../services/api.service';
#Component({
selector: 'app-data',
templateUrl: './data.component.html',
styleUrls: ['./data.component.css']
})
export class DataComponent implements OnInit{
udemydata = [];
constructor(private apiService: ApiService) {
}
ngOnInit() {
this.apiService.getCoupen().subscribe((data: any[]) => {
this.udemydata = data;
console.log(data);
},
error => {
console.log('err', error);
}
);
}
}
this is my component.html file
<table datatable [dtOptions]="dtOptions" class="table align-items-center table-flush">
<thead>
<tr>
<th scope="col">S.No</th>
<th scope="col">course</th>
<th scope="col">Link</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of udemydata; let i = index;">
<td>{{i+1}}</td>
<td>{{data["courseidhref"]}}</td>
<td><a href ="{{data['courseidhref']}}" target="_blank"><button class="btn btn-icon btn-3 btn-primary" type="button">
<span class="btn-inner--icon"><i class="ni ni-send"></i></span>
<span class="btn-inner--text">Enroll Now</span>
</button></a></td>
</tbody>
</table>
First of all, note that Angular runs in user's browser, so you want to use the URL class, instead of Node's url module, as that is only available in Node runtime.
The, we can break down the process into a few steps:
const url = 'https://www.udemy.com/course/technology-strategy-success/?couponCode=05DIwC2320';
// first, convert to URL class so that it can do the parsing for us.
const parsedUrl = new URL(url);
// we want to ignore the host and query string, so we only need the pathname, as you have yourself discovered.
const pathName = parsedUrl.pathname;
// then, let's split the pathname on any "/" characters.
const urlParts = pathName.split('/');
// this produces some empty strings, so let's get rid of them
const nonEmptyParts = urlParts.filter(x => x !== '');
// now we are left with proper url parts.
// In our case: [ "course", "technology-strategy-success" ]
// Assuming that the last element is always the course name:
const coursePart = nonEmptyParts.pop(); // or, nonEmptyParts[nonEmptyParts.length - 1]
// Finally, let's get rid of the hyphens, replacing them with spaces.
// The regex has two parts:
// 1. /-/ stands for match hyphens
// 2. g stands for "global" - we want to replace ALL hyphens, not just the first one
const courseName = coursePart.replace(/-/g, ' ');
If you want to add a bit more sugar, you could also change the first letter of the course title to be a capital.
const title = courseName[0].toUpperCase() + courseName.slice(1);
// Technology strategy success
If you want to capitalize every word:
const title = courseName.split(' ')
.map(word => word[0].toUpperCase() + word.slice(1))
.join(' ');
// Technology Strategy Success
Now, to show it in Angular you could go about it in a few ways:
After you receive the data from your service, convert it so that the data also has the course title.
Create a method in your component that converts url to course title and call it in the template: <td>{{convertHrefToTitle(data.courseidhref)}}</td>
Create a courseTitle Pipe that transforms hrefs to titles. You would use it like so:
<td>{{data.courseidhref | courseTitle}}</td>
Option 1 is fairly simple. When we get the data, we transform it once.
Option 2 is very simple too, but the function will run VERY frequently, on every change detection cycle. This might affect performance if used without thinking.
Option 3 is slightly more complicated, but it will NOT run on change detection cycle unless the href itself has changed. Read more about pipes ion official docs.
Here's an example of how to use Option 1:
Given interfaces
interface OriginalData {
courseidhref: string;
}
interface TransformedData {
courseidhref: string;
title: string;
}
transformData(data: OriginalData ): TransformedData {
return {...data, title: this.hrefToTitle(data.courseidhref)}
}
hrefToTitle(href: string): string {
// paste the solution from above into here
}
ngOnInit() {
this.apiService.getCoupen().subscribe((data: any[]) => {
const transformedData = data.map(course => this.transformData(course));
this.udemydata = transformedData;
console.log(data, transformedData);
},
error => {
console.log('err', error);
}
);
}
Finally, in your template you can do
<td>{{data.title}}</td>
<td><a href ="{{data.courseidhref}}" target="_blank">...

Reactjs frontend gets error when backend runs

I'm using React Js as frontend and node express as backend. When I start the my frontend using npm start it runs without errors but when I start my backend too then it throws this error: TypeError: Cannot read property 'map' of undefined and I could not find any solution for this.
Here's the code where the error is:
import React, { Component } from 'react'
import ApiService from "../../service/ApiService";
import SearchField from "./SearchField";
class ListModuleComponent extends Component {
constructor(props) {
super(props)
this.state = {
modules: [],
message: null
}
this.deleteModule = this.deleteModule.bind(this);
this.editModule = this.editModule.bind(this);
this.addModule = this.addModule.bind(this);
this.reloadModuleList = this.reloadModuleList.bind(this);
}
componentDidMount() {
this.reloadModuleList();
}
reloadModuleList() {
ApiService.fetchModules()
.then((res) => {
this.setState({ modules: res.data.result })
});
}
deleteModule(moduleId) {
ApiService.deleteModule(moduleId)
.then(res => {
this.setState({ message: 'Delete successful.' });
this.setState({ modules: this.state.modules.filter(module => module.id !== moduleId) });
})
}
editModule(id) {
window.localStorage.setItem("moduleId", id);
this.props.history.push('/edit-module');
}
addModule() {
window.localStorage.removeItem("moduleId");
this.props.history.push('/add-module');
}
render() {
return (
<div>
<h2 className="text-center">Modul data</h2>
<button className="btn btn-danger" style={{ width: '100px' }} onClick={() => this.addModule()}>Add</button>
<SearchField />
<table className="table table-striped">
<thead>
<tr>
<th className="hidden">Id</th>
<th>Id</th>
<th>Name</th>
{/* <th>Key</th> */}
<th>Default value</th>
<th>Description</th>
<th>State</th>
</tr>
</thead>
<tbody>
{
this.state.modules.map( // Error throws on this line //
module =>
<tr key={module.id}>
<td>{module.moduleName}</td>
<td>{module.moduleDefaultValue}</td>
<td>{module.description}</td>
<td>{module.isActive}</td>
<td>
<button className="btn btn-success" onClick={() => this.deleteModule(module.id)}> Delete</button>
<button className="btn btn-success" onClick={() => this.editModule(module.id)} style={{ marginLeft: '20px' }}>Edit</button>
</td>
</tr>
)
}
</tbody>
</table>
</div>
);
}
}
export default ListModuleComponent;
So the error only show up if my backend starts and I don't know if it is caused by backend or frontend, only see the error for the React frontend side. I can provide more code if needed.
res.result.data is most likely undefined. You could solve this in 2 ways:
1. Prevent undefined in your state.
You could set your state to an empty array in case res.result.data is undefined like so:
this.setState({ modules: res.data.result || [] });
This will make sure your state always contains an array even if the backend provides no data.
2. Do a null-check before rendering your data.
Check if your this.state.modules holds a value before rendering your content.
<div>
{this.state.modules && this.state.modules.map(module => {
// Code
}}
</div>
The default state for modules is an array, this means that mapping over it is okay, so if it doesnt fetch any data then the component will render just fine.
this.state = {
modules: [],
message: null
}
When the backend has been started the reload modules method is setting the modules to be res.data.result
The error is Cannot read property 'map' of undefined.
Because of this I think res.data.result is undefined.
to fix this check what res is and make sure the thing you are setting in state is the array of data
Seems like a null check would fix the obvious problems here.
{
this.state.modules instanceof Array && this.state.modules.map(
module => { /*...*/ }
)
}
Nevertheless, I strongly assume that the backend has already delivered the data correctly. Also your code has an assumption that the array is always there and I cannot find a place where it has been deleted/false initialized. So I Just assume that the backend returns you an undefined/null value, which would also be covered by this check. So maybe investigate your backend whether it returns a null value.

ReactJS : Async function with axios call makes axios call in componentDidUpdate to return promise

I have the code of my component like :
import React, { Component } from 'react';
import axios from 'axios';
import "bootstrap/dist/css/bootstrap.min.css";
import {
Table
} from 'reactstrap';
const Adhoc = async (props) => {
let cost = await props.cost(props.adhoc._id)
return(
<tr>
<td>{props.adhoc.jIssue}</td>
<td>{props.adhoc.paid ? "Paid" : "Not paid"}</td>
<td>APP{props.adhoc.sprint}</td>
<td>£{cost.data[0]}</td>
</tr>
)}
export default class QAdhocsDisplay extends Component {
constructor(props) {
super(props);
this.costingAdhoc = this.costingAdhoc.bind(this)
this.state = {
adhocs: []
};
}
componentDidMount() {
axios.get('http://localhost:5000/adhocs/retrieve')
.then(response => {
this.setState({ adhocs: response.data })
})
.catch((error) => {
console.log(error);
})
}
async costingAdhoc(id) {
const data = await axios.get('http://localhost:5000/jira/issue/' + id)
.catch((error) => {
console.log(error);
})
return data;
}
adhocsList() {
return this.state.adhocs.map(currentadhoc=> {
return <Adhoc adhoc={currentadhoc} cost={this.costingAdhoc} key={currentadhoc._id}/>;
})
}
render(){
return (
<div className="toborder" style = {{paddingBottom: "59px"}}>
<div className="display" style ={{backgroundColor: "#5394b2"}}>
<h5 style = {{padding:"13px"}}>Adhoc status</h5>
</div>
<div className="table">
<Table size="sm" bordered striped>
<thead className="thead-light">
<tr className="adhocs">
<th className="sticky-column medium" >Adhoc issue</th>
<th className="sticky-column medium" >Payment status</th>
<th className="sticky-column medium" >Sprint</th>
<th className="sticky-column medium" >Projected cost</th>
</tr>
</thead>
<tbody>
{ this.adhocsList() }
</tbody>
</Table>
</div>
</div>
)}
}
My issue is that I have the function costingAdhoc(id) which I pass as a prop to the child component Adhoc. To be able to access the information from the axios call I need these both functions to be async.
A child component of type Adhoc will be rendered for each item in the state that will get mapped in the function adhocsList(). For some reason this causes the axios call in the componentDidUpdate() to throw this error:
Objects are not valid as a React child (found: [object Promise]). If
you meant to render a collection of children, use an array instead.
And the error points to the line where I set the state. This means that the costingAdhoc(id) function async nature causes my axios call in the componentDidUpdate() function only return a promise and not the actual data.
Your problem that is Adhoc component which you're declaring as a child component is actually a promise.
Why?
A function that is declared as async returns promise by default, so even if you return:
<tr>
<td>{props.adhoc.jIssue}</td>
<td>{props.adhoc.paid ? "Paid" : "Not paid"}</td>
<td>APP{props.adhoc.sprint}</td>
<td>£{cost.data[0]}</td>
</tr>
you're actually returning it wrapped inside a promise. React components cannot be promises.

Get Dynamically created table Data in React Row

I am more familiar with NodeJs than react. I have build a react component that searches for user input and provides the output in a table format based on the value that the user has typed into the search input form. This is working as I want and the code for the module is below:
import React, { Component } from 'react';
import axios from 'axios';
import Suggestions from './Suggestions';
// API url
const API_URL = 'http://localhost:3000/api/file_infos'
class Search extends Component {
state = {
query: '',
results: []
}
getCount = () => {
axios.get(`${API_URL}count?filter[where][id][regexp]=/${this.state.query}/i`)
.then(count => {
this.setState({
results: count.data
})
})
}
// query loop back API for matching queries base on text input
getInfo = () => {
axios.get(`${API_URL}?filter[where][id][regexp]=/${this.state.query}/i&filter[limit]=20`)
.then(response => {
this.setState({
results: response.data
})
})
}
// check to see if input on the search bar has changed and update the search query accordingly
handleInputChange = () => {
this.setState({
query: this.search.value
}, () => {
if (this.state.query && this.state.query.length > 1) {
if (this.state.query) {
this.getInfo()
}
} else if (!this.state.query) {
}
})
}
// render form and pass results back to the home component
render() {
return (
<div>
<form>
<input
placeholder="Search for..."
ref={input => this.search = input}
onChange={this.handleInputChange}
/>
</form>
<Suggestions results={this.state.results} />
</div>
)
}
}
export default Search
The second module is the suggestions module that displays the output in the table format.
The next portion of the app I am building will open a file based on the table row that the user selected. I want that table data returned to a function so that I can make an http post request to my API that will in turn open the file using a NodeJS module.
I want the suggestions component to return the value of the data items in the table cells so that the data can be used to send to the API in order to open my files. The code I have come up with so far is only returning an undefined error.
Below is what I currently have:
import React from 'react';
// return results in a table format based on the text input entered
const Suggestions = (props) => {
const state = {
results: []
}
const handleFormOpen = () => {
this.setState({
results: this.results.value
},
console.log(this.state.results)
)
}
const options = props.results.map(r => (
<tr key={r.id} ref={tr => this.results = tr} onClick={handleFormOpen.bind(this)}>
<td>{r.id}</td>
<td>{r.OriginalPath}</td>
<td>{r.CreateDate}</td>
<td>{r.AccessDate}</td>
<td>{r.WriteDate}</td>
<td><i className="fas fa-book-open"></i></td>
</tr>
))
return <table className="striped responsive-table">
<thead>
<tr>
<th>File Name</th>
<th>Parent Directory</th>
<th>Creation Date</th>
<th>Access Date</th>
<th>Write Date</th>
<th>Open File</th>
</tr>
</thead>
<tbody>
{options}
</tbody>
</table>
}
export default Suggestions;
I am really unsure at this point if I am trying to tackle this issue in the correct way. I am thinking that maybe the suggestions component may need to be turned into a full class extending component but I am fairly lost at this point. Can someone please kindly point out my folly and get me going in the right direction?
UPDATE
As requested in the comments here is the error log from my browser:
Suggestions.js:10 Uncaught TypeError: Cannot read property 'results' of undefined
at Object.handleFormOpen (Suggestions.js:10)
at HTMLUnknownElement.callCallback (react-dom.development.js:145)
at Object.invokeGuardedCallbackDev (react-dom.development.js:195)
at invokeGuardedCallback (react-dom.development.js:248)
at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:262)
at executeDispatch (react-dom.development.js:593)
at executeDispatchesInOrder (react-dom.development.js:615)
at executeDispatchesAndRelease (react-dom.development.js:713)
at executeDispatchesAndReleaseTopLevel (react-dom.development.js:724)
at forEachAccumulated (react-dom.development.js:694)
at runEventsInBatch (react-dom.development.js:855)
at runExtractedEventsInBatch (react-dom.development.js:864)
at handleTopLevel (react-dom.development.js:4857)
at batchedUpdates$1 (react-dom.development.js:17498)
at batchedUpdates (react-dom.development.js:2189)
at dispatchEvent (react-dom.development.js:4936)
at interactiveUpdates$1 (react-dom.development.js:17553)
at interactiveUpdates (react-dom.development.js:2208)
at dispatchInteractiveEvent (react-dom.development.js:4913)
First thing Since your Suggestions component plays with state, I would recommend you to go with statefull component.
Stateless component is meant for getting props and returning jsx elements, there wont be any state mutations in stateless component. This is called pure function in javascript. Hope this makes clear.
Also since you declared handleFormOpen as an arrow function you no need to do binding. binding takes care automatically by arrow function. If you don't want to use arrow function and you want to bind it then do the binding always in constructor only but don't do binding anywhere in the component like you did in map.
PFB corrected Suggestions component code
import React, { Component } from 'react';
// return results in a table format based on the text input entered
export default class Suggestions extends Component {
constructor(props){
super(props);
this.state = {
results: [],
value: ""
}
}
handleFormOpen = (path, id) => {
console.log("id", id, path);//like wise pass value to this function in .map and get the value here
this.setState({
value: id
});
}
render(){
const { results } = this.props;
return (<div>
<table className="striped responsive-table">
<thead>
<tr>
<th>File Name</th>
<th>Parent Directory</th>
<th>Creation Date</th>
<th>Access Date</th>
<th>Write Date</th>
<th>Open File</th>
</tr>
</thead>
<tbody>
{Array.isArray(results) && results.length > 0 && results.map(r => (
<tr key={r.id} ref={tr => this.results = tr} onClick={() => this.handleFormOpen(r.OriginalPath, r.id)}>
<td>{r.id}</td>
<td>{r.OriginalPath}</td>
<td>{r.CreateDate}</td>
<td>{r.AccessDate}</td>
<td>{r.WriteDate}</td>
<td><i className="fas fa-book-open"></i></td>
</tr>
))}
</tbody>
</table>
</div>)
}
}
export default Suggestions;
You are using states in Functional Component, You need to use React Component
import React from 'react';
// return results in a table format based on the text input entered
class Suggestions extends React.Component {
constructor(props) {
super(props);
this.state = {
results: [],
}
}
handleFormOpen = () => {
this.setState({
results: this.results.value
},
console.log(this.state.results)
)
}
render () {
const options = this.props.results.map(r => (
<tr key={r.id} ref={tr => this.results = tr} onClick={handleFormOpen.bind(this)}>
<td>{r.id}</td>
<td>{r.OriginalPath}</td>
<td>{r.CreateDate}</td>
<td>{r.AccessDate}</td>
<td>{r.WriteDate}</td>
<td><i className="fas fa-book-open"></i></td>
</tr>
))
return (
<table className="striped responsive-table">
<thead>
<tr>
<th>File Name</th>
<th>Parent Directory</th>
<th>Creation Date</th>
<th>Access Date</th>
<th>Write Date</th>
<th>Open File</th>
</tr>
</thead>
<tbody>
{options}
</tbody>
</table>
)
}
}
export default Suggestions;

Resources