Make table cell clickable in React - javascript

When the user clicks the tableCell text below, he should be navigated to http://localhost:3000/crayons/${rows.id} <- This exists in my react-router-dom
I am not sure how to edit the below code to do the following
<TableBody>
{props.rows.slice(page).map(row => (
<TableCell align="center">{row.crayon_color}</TableCell>
</TableBody>
What I tried
<TableCell align="center" numeric component="a" href=`http://localhost:3000/crayons/${rows.id}`> {row.crayon_color}</TableCell>

Try using a callback for the table cell that pushes the routes into history, so with that your code would resemble something like this:
import React from 'react';
import {withRouter} from 'react-router-dom';
const ExampleComponent = (props) => {
// ...other component variables
callback = () => {
props.history.push(`crayons/${rows.id}`)
}
return (
<TableCell align="center" onClick={callback}>{row.crayon_color}</TableCell>
);
}
export default withRouter(ExampleComponent);

EDIT updated live demo to show how to handle dynamic objects in an array.
EDIT 2 updated live demo and the code below to reflect how to use URL params with dynamic objects..
I believe the easiest way to accomplish this is by using a <Link/> component from react-router-dom.
Live Demo Found Here
This is what the BrowserRouter needs to look like:
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/crayons" component={Crayons} />
<Route path="/crayons/:id" component={Crayons} />
{/* MUST BE THE LAST ROUTE IN THIS LIST!!!! */}
<Route component={FourZeroFour} />
</Switch>
Then inside of your Crayons.js page, you can access the URL param, in this case id like: props.match.params.id..
Demo Table code:
// Build 'fake data' for table
const rows = Array.from(Array(10).keys()).map(item => {
return {
data: "Crayon",
count: Math.floor(Math.random() * 100),
id: item + 1
}
})
export default function Home() {
const classes = useStyles();
return (
<>
<h1>Welcome to my app</h1>
<Paper className={classes.root}>
<Table className={classes.table}>
<TableHead>
<TableRow>
<TableCell>Data</TableCell>
<TableCell>ID</TableCell>
<TableCell>Count</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map(row => {
return (
<TableRow key={row.id}>
<TableCell component="th" scope="row">
{row.id
? <Link to={`/crayons/${row.id}`}>{row.data}</Link>
: row.data}
</TableCell>
<TableCell>
{row.id}
</TableCell>
<TableCell>
{row.count}
</TableCell>
</TableRow>
)
})}
</TableBody>
</Table>
</Paper>
</>
)
}

You can use library React Router Dom.
Solution is simple add withRouter HOC to your component.
import { withRouter } from 'react-router-don'
const Component = () => (
<TableCell align="centre" onClick={()=>props.history.push(`${rows.id}`)}>{row.crayon_color}</TableCell>
)
export default withRouter(Component);

Related

i am trying to render Svg icons in a table , using material ui , in a react application. However, i see duplicate icons for different rows, any ideas?

I have an array of objects, where each object has a cryptocurrency-Id. i am using map to render a table and for rendering the token-image in the table i am calling a function: find_corresponding_icon(crypto-name), this function takes the crypto-name as a parameter and returns an image corresponding to it.I am seeing duplicate images rendering in my table.
import {ReactComponent as EthIcon} from '../../assets/eth.svg'
import {ReactComponent as DaiIcon} from '../../assets/dai.svg'
import {ReactComponent as UsdtIcon} from '../../assets/usdt.svg'
useEffect(()=>{
async function api_call(){
let res = await getTokenInfo()
setCurrecnyInfo(res.data.message) //setting state with an array of json objects
//currencyInfo=[{currencyId:1,tokenName:'Ethereum',Amount:312},
//{currencyId : 2, tokenName:'Dai',Amount:182},{currencyId : 3
, // tokenName:'USDT',Amount:882}]
}
api_call();
},[])
function find_corresponding_icon(CurrencyId){
if(CurrencyId === 1)
return <EthIcon />
else if(CurrencyId === 2)
return <DaiIcon />
else if(CurrencyId === 3)
return <UsdtIcon />
}
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>TokenName</TableCell>
<TableCell>Name</TableCell>
<TableCell>Amount($)</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map((row,id) => (
<TableRow key={id}>
<TableCell component="th" scope="row">{find_corresponding_icon(row.currencyId)}</TableCell>
<TableCell align="right">{row.tokenName}</TableCell>
<TableCell align="right">{row.Amount}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
)
The result looks like so:
i am very sure all the icons look different, so there should not be a repetition

How to create a reusable component for large number of Buttons that open a Form

library used: mui 5.4.1
To create a TableCell containing an IconButton that opens a Form, the code is written as follows.
const data = [
{
id: "001",
name: "A",
price: 2000
},
{ id: "002", name: "B", price: 100 },
...
];
const SandboxTable = () => {
return (
<ThemeProvider theme={muiTheme}>
<TableContainer>
<Table>
...
{data.map((datum) => (
<TableRow key={datum.id}>
<TableCell>{datum.id}</TableCell>
<TableCell>{datum.name}</TableCell>
<TableCell>{datum.price}</TableCell>
<ApproveFormButtonCell
toolTip={"approve"}
id = {datum.id}
IconComponent={<CheckCircleOutlineIcon color={"success"} />}
/>
<RejectFormButtonCell
toolTip={"Reject"}
name = {datum.name}
IconComponent={<CancelOutlinedIcon color="error" />}
/>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</ThemeProvider>
);
};
const ApproveFormButtonCell = ({ toolTip, IconComponent }) => {
const usePopoverProps = usePopover();
return (
<TableCell>
<IconButtonWithTooltip
toolTip={toolTip}
onClick={usePopoverProps.handleOpen}
IconComponent={IconComponent}
/>
<BasePopover usePopverProps={usePopoverProps}>
<ApproveForm id={id} handleClose={usePopoverProps.handleClose} />
</BasePopover>
</TableCell>
);
};
Then I have to create a new ButtonCell component every time a new button is added.
To avoid this, when ApproveForm is used in SandboxTable, handleClose could not be received.
<ApproveFormButtonCell
toolTip={"approve"}
id = {datum.id}
IconComponent={<CheckCircleOutlineIcon color={"success"} />}
/>
<ApproveForm handleClose={??}/>
</ApproveFormButtonCell>
I need a lot of buttons open form.
Any good answers to solve this situation?
codesandbox
To keep from making a one-off of every sort and type of form button cell component you can abstract the common behavior/UI, i.e. the IconButtonWithTooltip and BasePopover components, into a generic component and pass in as a prop the content that is different. In this case it seems the form component is what is different.
Create a general purpose component that utilizes the power of a render prop, i.e. a prop that is a function called during the render. This render prop will pass the close handler as an argument.
Example:
const FormButton = ({ toolTip, IconComponent, renderForm }) => {
const popoverProps = usePopover();
return (
<>
<IconButtonWithTooltip
toolTip={toolTip}
onClick={popoverProps.handleOpen}
IconComponent={IconComponent}
/>
<BasePopover usePopverProps={popoverProps}>
{renderForm({ handleClose: popoverProps.handleClose })}
</BasePopover>
</>
);
};
Example usage:
import CheckCircleOutlineIcon from "#mui/icons-material/CheckCircleOutline";
import CancelOutlinedIcon from "#mui/icons-material/CancelOutlined";
import FormButton from "./FormButton";
import RejectForm from "./RejectForm";
import ApproveForm from "./ApproveForm";
...
<TableBody>
{data.map((datum) => (
<TableRow key={datum.id}>
<TableCell>{datum.id}</TableCell>
<TableCell>{datum.name}</TableCell>
<TableCell>{datum.price}</TableCell>
<TableCell>
<FormButton
toolTip={"approve"}
IconComponent={<CheckCircleOutlineIcon color={"success"} />}
renderForm={({ handleClose }) => (
<ApproveForm id={datum.id} handleClose={handleClose} />
)}
/>
</TableCell>
<TableCell>
<FormButton
toolTip={"Reject"}
IconComponent={<CancelOutlinedIcon color="error" />}
renderForm={({ handleClose }) => (
<RejectForm handleClose={handleClose} name={datum.name} />
)}
/>
</TableCell>
</TableRow>
))}
</TableBody>

Error in React while using Router Expected a string or a class/function but got: undefined

I am trying to redirect to another page. I am new to React. I used Router for moving to other page. However i get the following error:
Here is my code:
import Head from 'next/head';
import { Box, Container, Grid, Pagination } from '#mui/material';
import { products } from '../__mocks__/products';
import { ProductListToolbar } from '../components/product/product-list-toolbar';
import { ProductCard } from '../components/product/product-card';
import { DashboardLayout } from '../components/dashboard-layout';
import { CustomerListResults } from '../components/trip/trip-list-results';
import { customers } from '../__mocks__/customers';
import { trips } from '../__mocks__/trips';
import { TripListResults } from '../components/customer/customer-list-results';
import React, { BrowserRouter as Router,
Switch,
Route,
Redirect, useEffect, useState } from "react";
import {
Avatar,
Card,
Checkbox,
Table,
TableBody,
TableCell,
TableHead,
TablePagination,
TableRow,
Typography,
Button
} from '#mui/material';
import NextLink from 'next/link';
const TripRequests = () => {
const [acceptState, setAcceptState] = useState(true);
const accept = () => setAcceptState(false);
return (
<>
<Router>
<Switch>
<Route exact path="/" component={DashboardLayout } />
<Head>
<title>
Trip Requests
</title>
</Head>
<Box
component="main"
sx={{
flexGrow: 1,
py: 8
}}
>
<Container maxWidth={false}>
<Box sx={{ mt: 3 }}>
{/* <CustomerListResults customers={trips} /> */}
<h2>Trip Requests (1)</h2>
</Box>
<Box sx={{ minWidth: 1050, mt: 3 }}>
<Table>
<TableHead>
<TableRow>
<TableCell padding="checkbox">
{/* <Checkbox
// checked={selectedCustomerIds.length === customers.length}
color="primary"
// indeterminate={
// selectedCustomerIds.length > 0
// && selectedCustomerIds.length < customers.length
// }
// onChange={handleSelectAll}
/> */}
</TableCell>
{/* <TableCell>
Trip Id
</TableCell> */}
<TableCell>
Customer
</TableCell>
<TableCell>
Departure
</TableCell>
<TableCell>
Destination
</TableCell>
<TableCell>
Truck / Driver
</TableCell>
<TableCell>
Action
</TableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow
hover
// key={customer.id}
// selected={selectedCustomerIds.indexOf(customer.id) !== -1}
>
<TableCell padding="checkbox">
{/* <Checkbox
checked={selectedCustomerIds.indexOf(customer.id) !== -1}
onChange={(event) => handleSelectOne(event, customer.id)}
value="true"
/> */}
</TableCell>
<TableCell>
Rohan Joshi
</TableCell>
<TableCell>
<Box
sx={{
alignItems: 'center',
display: 'flex'
}}
>
{/* <Avatar
src={customer.avatarUrl}
sx={{ mr: 2 }}
>
{getInitials(customer.name)}
</Avatar> */}
<Typography
color="textPrimary"
variant="body1"
>
A-50, Sec 67, Noida
</Typography>
</Box>
</TableCell>
<TableCell>
HUDA City Center
</TableCell>
<TableCell>
Truck #123 / Ravi Shukla
</TableCell>
<TableCell>
{acceptState ? (
<><Button onClick={accept}>Accept</Button><Button>Decline</Button></>
) : <p>Pending Payment</p>}
</TableCell>
{/* <TableCell>
{format(customer.createdAt, 'dd/MM/yyyy')}
</TableCell> */}
</TableRow>
</TableBody>
</Table>
</Box>
</Container>
</Box>
{/* <Redirect to="/" /> */}
</Switch>
</Router>
</>
);
};
TripRequests.getLayout = (page) => (
<DashboardLayout>
{page}
</DashboardLayout>
);
export default TripRequests;
Import Router objects from react-router-dom instead of react
import {
BrowserRouter as Router,
Switch,
Route,
Redirect
} from "react-router-dom";
In the latest react-router-dom, the route should be configured like below. Initially you need to import all the dependencies from react-router-dom. Also, all the routes should be wrapped inside <Routes></Routes>.
import './App.css';
import Home from './Components/Home'
import Functioncontext from './Components/Functioncontext'
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
function App() {
return (
<div className="App">
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/context" element={<Functioncontext />} />
</Routes>
</Router>
</div>
);
}
export default App;
The above code works on "react-router-dom": "^6.3.0". Before react-router-dom version 6. It has to be configured in the different way.

TypeError: language.map is not a function when getting data using axios

This is my component here I'm using MUI for table. I'm getting data from API and I also use map method to get my data but I'm getting error that says:
TypeError: language.map is not a function
But when put language in square it does not error but also not show any data on UI according to me my code is correct can anyone help me.
Language.js
import Table from "#mui/material/Table";
import TableBody from "#mui/material/TableBody";
import TableCell from "#mui/material/TableCell";
import TableContainer from "#mui/material/TableContainer";
import TableHead from "#mui/material/TableHead";
import TableRow from "#mui/material/TableRow";
import Paper from "#mui/material/Paper";
import axios from "axios";
import { useState, useEffect } from "react";
const Languages = () => {
const [language, setLanguage] = useState([]);
useEffect(() => {
axios
.get(
"https://omxdgcc23c.execute-api.ap-south-1.amazonaws.com/dev/api/misc/languages?
userId=0x60588910"
)
.then((res) => {
console.log(res.data);
setLanguage(res.data);
})
.catch((err) => {
console.log(err);
});
}, []);
return (
<div>
<h1>Languages</h1>
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} size="small" aria-label="a dense table">
<TableHead>
<TableRow>
<TableCell>Id</TableCell>
<TableCell align="right">English Text</TableCell>
<TableCell align="right"> Text</TableCell>
<TableCell align="right">Category</TableCell>
<TableCell align="right">Order Index</TableCell>
<TableCell align="right">Language Code</TableCell>
<TableCell align="right">Created Time</TableCell>
<TableCell align="right">Updated Time</TableCell>
</TableRow>
</TableHead>
<TableBody>
{language.map((languages) => {
return (
<TableRow key={languages.id}>
<TableCell component="th" scope="row">
{languages.uid}
</TableCell>
<TableCell align="right">{languages.engText}</TableCell>
<TableCell align="right">{languages.text}</TableCell>
<TableCell align="right">{languages.category}</TableCell>
<TableCell align="right">{languages.index}</TableCell>
<TableCell align="right">{languages.code}</TableCell>
<TableCell align="right">{languages.createdAt}</TableCell>
<TableCell align="right">{languages.updatedAt}</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
</div>
);
};
export default Languages;
See the axios API here, the fetched data is also stored in the data property, so you have to access it like this:
axios.get('...').then(res => setLanguage(res.data.data));
Check the length of language state, if it is greater than 0 after only you can map the language array,
Kindly, check with below code,
{ language && language.length > 0 && language.map((languages) => {
return (
<TableRow key={languages.id}>
<TableCell component="th" scope="row">
{languages.uid}
</TableCell>
<TableCell align="right">{languages.engText}</TableCell>
<TableCell align="right">{languages.text}</TableCell>
<TableCell align="right">{languages.category}</TableCell>
<TableCell align="right">{languages.index}</TableCell>
<TableCell align="right">{languages.code}</TableCell>
<TableCell align="right">{languages.createdAt}</TableCell>
<TableCell align="right">{languages.updatedAt}</TableCell>
</TableRow>
);
})}
The api response is of the format:
{
"statusCode": 200,
"data": [
{...},
{...}
]
}
So when setting languages you need to save the data property of the response's data object.
setLanguage(_.get(res, 'data.data', []));
Then, languages will always be a list, and you won't need to check it throughout the rest of your function.
You may need to check the response in your useEffect block if you want to do some error handling against a bad api response. But that's now in one place rather than throughout the rest of the function.

Can't read property 'map' of undefined in React app

I am trying to develop a simple React app, with crud operations, but I can't even list my objects, which are stored into a sql database. I followed this example for the frontend: https://github.com/only2dhir/react-js-example
and I continued it, adding the component for my objects.
In my application, I have doctors and patients. A patient is assigned to a doctor, so a doctor can have one or more patients. In order to do this, I create my jsx file, ListCaregiverComponent.jsx, where I did that :
import React, { Component } from 'react'
import ApiServiceCaregiver from "../../service/ApiServiceCaregiver";
import ApiServicePatient from "../../service/ApiServicePatient";
import Table from '#material-ui/core/Table';
import TableBody from '#material-ui/core/TableBody';
import TableCell from '#material-ui/core/TableCell';
import TableHead from '#material-ui/core/TableHead';
import TableRow from '#material-ui/core/TableRow';
import Typography from '#material-ui/core/Typography';
class ListCaregiverComponent extends Component {
constructor(props) {
super(props)
this.state = {
caregivers: [],
patients: [],
message: null
}
this.deleteCaregiver = this.deleteCaregiver.bind(this);
this.editCaregiver = this.editCaregiver.bind(this);
this.addCaregiver = this.addCaregiver.bind(this);
this.reloadCaregiverList = this.reloadCaregiverList.bind(this);
this.reloadPatientList = this.reloadPatientList.bind(this);
}
componentDidMount() {
this.reloadCaregiverList();
this.reloadPatientList();
}
reloadCaregiverList() {
ApiServiceCaregiver.fetchCaregivers()
.then((res) => {
this.setState({caregivers: res.data.result})
});
}
reloadPatientList() {
ApiServicePatient.fetchPatients()
.then((res) => {
this.setState({patients: res.data.result})
});
}
deleteCaregiver(userId) {
ApiServiceCaregiver.deleteCaregiver(userId)
.then(res => {
this.setState({message : 'User deleted successfully.'});
this.setState({caregivers: this.state.caregivers.filter(user => user.id !== userId)});
})
}
editCaregiver(id) {
window.localStorage.setItem("userId", id);
this.props.history.push('/edit-caregiver');
}
addCaregiver() {
window.localStorage.removeItem("userId");
this.props.history.push('/add-caregiver');
}
render() {
return (
<div>
<br></br>
<br></br>
<Typography variant="h4" style={style}>Caregiver Details</Typography>
<br></br>
<br></br>
<Table>
<TableHead>
<TableRow>
<TableCell>Id</TableCell>
<TableCell align="right">Name</TableCell>
<TableCell align="right">Birth Date</TableCell>
<TableCell align="right">Gender</TableCell>
<TableCell align="right">Address</TableCell>
<TableCell align="center">Patients</TableCell>
</TableRow>
</TableHead>
<TableBody>
{this.state.caregivers.map(({ id, name, birthDate, gender, address, patients = [] }) =>(
<TableRow key={id}>
<TableCell component="th" scope="row">
{id}
</TableCell>
<TableCell align="right">{name}</TableCell>
<TableCell align="right">{birthDate}</TableCell>
<TableCell align="right">{gender}</TableCell>
<TableCell align="right">{address}</TableCell>
<TableCell align="right">
<TableRow>
<TableCell align = "right" >Id</TableCell>
<TableCell align = "right" >Name</TableCell>
<TableCell align="right">Birth Date</TableCell>
<TableCell align="right">Gender</TableCell>
<TableCell align="right">Address</TableCell>
<TableCell align="right">Medical Record</TableCell>
</TableRow>
{patients.map(({ id, name, birthDate, gender, address, medicalRecord })=> {
return (
<TableRow key={id}>
<TableCell component="th" scope="row">
{id}
</TableCell>
<TableCell align="right">{name}</TableCell>
<TableCell align="right">{birthDate}</TableCell>
<TableCell align="right">{gender}</TableCell>
<TableCell align="right">{address}</TableCell>
<TableCell align="right">{medicalRecord}</TableCell>
</TableRow>
)
})}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
}
const style ={
display: 'flex',
justifyContent: 'center'
}
export default ListCaregiverComponent;
The ListPatientComponent.jsx looks like this :
import React, { Component } from 'react'
import ApiServicePatient from "../../service/ApiServicePatient";
import Table from '#material-ui/core/Table';
import TableBody from '#material-ui/core/TableBody';
import TableCell from '#material-ui/core/TableCell';
import TableHead from '#material-ui/core/TableHead';
import TableRow from '#material-ui/core/TableRow';
import Typography from '#material-ui/core/Typography';
class ListPatientComponent extends Component {
constructor(props) {
super(props)
this.state = {
patients: [],
message: null
}
this.deletePatient = this.deletePatient.bind(this);
this.editPatient = this.editPatient.bind(this);
this.addPatient = this.addPatient.bind(this);
this.reloadPatientList = this.reloadPatientList.bind(this);
}
componentDidMount() {
this.reloadPatientList();
}
reloadPatientList() {
ApiServicePatient.fetchPatients()
.then((res) => {
this.setState({patients: res.data.result})
});
}
deletePatient(userId) {
ApiServicePatient.deletePatient(userId)
.then(res => {
this.setState({message : 'User deleted successfully.'});
this.setState({patients: this.state.patients.filter(user => user.id !== userId)});
})
}
editPatient(id) {
window.localStorage.setItem("userId", id);
this.props.history.push('/edit-patient');
}
addPatient() {
window.localStorage.removeItem("userId");
this.props.history.push('/add-patient');
}
render() {
return (
<div>
<br></br>
<br></br>
<Typography variant="h4" style={style}>Patient Details</Typography>
<br></br>
<br></br>
<Table>
<TableHead>
<TableRow>
<TableCell>Id</TableCell>
<TableCell align="right">Name</TableCell>
<TableCell align="right">Birth Date</TableCell>
<TableCell align="right">Gender</TableCell>
<TableCell align="right">Address</TableCell>
<TableCell align="right">Medical Record</TableCell>
<TableCell align="center">Medication Plans</TableCell>
</TableRow>
</TableHead>
<TableBody>
{this.state.patients.map(row => (
<TableRow key={row.id}>
<TableCell component="th" scope="row">
{row.id}
</TableCell>
<TableCell align="right">{row.name}</TableCell>
<TableCell align="right">{row.birthDate}</TableCell>
<TableCell align="right">{row.gender}</TableCell>
<TableCell align="right">{row.address}</TableCell>
<TableCell align="right">{row.medicalRecord}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
);
}
}
const style ={
display: 'flex',
justifyContent: 'center'
}
export default ListPatientComponent;
and it works.
I also added two new js files, ApiServicePatient.js and ApiServiceCaregiver.js :
import axios from 'axios';
const CAREGIVER_API_BASE_URL = 'http://localhost:8080/caregivers';
class ApiServiceCaregiver {
fetchCaregivers() {
return axios.get(CAREGIVER_API_BASE_URL);
}
fetchCaregiverById(caregiverId) {
return axios.get(CAREGIVER_API_BASE_URL + '/' + caregiverId);
}
deleteCaregiver(caregiverId) {
return axios.delete(CAREGIVER_API_BASE_URL + '/' + caregiverId);
}
addCaregiver(caregiver) {
return axios.post(""+CAREGIVER_API_BASE_URL, caregiver);
}
editCaregiver(caregiver) {
return axios.put(CAREGIVER_API_BASE_URL + '/' + caregiver.id, caregiver);
}
}
export default new ApiServiceCaregiver();
import axios from 'axios';
const PATIENT_API_BASE_URL = 'http://localhost:8080/patients';
class ApiServicePatient {
fetchPatients() {
return axios.get(PATIENT_API_BASE_URL);
}
fetchPatientById(userId) {
return axios.get(PATIENT_API_BASE_URL + '/' + userId);
}
deletePatient(userId) {
return axios.delete(PATIENT_API_BASE_URL + '/' + userId);
}
addPatient(user) {
return axios.post(""+PATIENT_API_BASE_URL, user);
}
editPatient(user) {
return axios.put(PATIENT_API_BASE_URL + '/' + user.id, user);
}
}
export default new ApiServicePatient();
Also, in App.js, I added :
import React from 'react';
import './App.css';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import ListUserComponent from "./component/user/ListUserComponent";
import AddUserComponent from "./component/user/AddUserComponent";
import EditUserComponent from "./component/user/EditUserComponent";
import ListPatientComponent from "./component/patient/ListPatientComponent";
import ListCaregiverComponent from "./component/caregiver/ListCaregiverComponent";
function App() {
return (
<div className="container">
<Router>
<div className="col-md-6">
<h1 className="text-center" style={style}>React User Application</h1>
<Switch>
<Route path="/" exact component={ListUserComponent} />
<Route path="/users" component={ListUserComponent} />
<Route path="/add-user" component={AddUserComponent} />
<Route path="/edit-user" component={EditUserComponent} />
<Route path="/patients" component={ListPatientComponent} />
<Route path="/caregivers" component={ListCaregiverComponent} />
</Switch>
</div>
</Router>
</div>
);
}
const style = {
color: 'red',
margin: '10px'
}
export default App;
It doesn't work, it only says :
Unhandled Rejection (TypeError): Cannot read property 'map' of undefined
and it indicates the lines with :
<TableCell align="right">{row.address}</TableCell>
{row.patients.map(row => (
In the backend application, the class Caregiver has a list of patients objects, mapped as one-to-many :
#OneToMany(mappedBy = "caregiver", fetch = FetchType.EAGER)
private List<Patient> patients;
Does anyone have some suggestions?
--------UPDATE AFTER FIRST ANSWERS---------
I no longer get that error, but I can't display in my table of caregivers the assigned patients. The corresponding TableCell s are empty for the patients of each caregiver. Why is happening this?
You do this.state.caregivers.map(row => and then {row.patients.map(row =>, but I don't see any indication that each caregivers element has a patients array property
Since you are using asynchronous call the javascript start rendering and for a few miliseconds "this.state.caregivers" has no value so you cannot map a null value it needs to be array null.
Make sure to add a condition to check first or declare "this.state.caregivers" as empty array in the constructor.
As mentioned in other answers, patients is maybe undefined for some rows, so you could assign it a default value using Destructuring:
{this.state.caregivers.map(({ id, name, birthDate, gender, address, patients = [] }) => (
<TableCell component="th" scope="row">
{id}
</TableCell>
<TableCell align="right">{name}</TableCell>
<TableCell align="right">{birthDate}</TableCell>
<TableCell align="right">{gender}</TableCell>
<TableCell align="right">{address}</TableCell>
{patients.map(row => (
...
Try to add before each map the property you want to map and && like this:
this.state.caregivers && this.state.caregivers.map
Do this for each map in your code.

Categories

Resources