I'm using a axios to get my api to display some data from it. This works fine.
I want to get each of value and display the returned data when I click "TableRow"
this is my json data.
I want to get id and use axios api like this.
const toDetails = (e) => {
e.preventDefault();
const getDetails = async () => {
const response = await axios.get(`api/firstmemory/${id}`);
setUserData(response.data.data);
}
getDetails();
}
inside return
return(
<TableContainer component={Paper}>
<Table className={classes.table}>
<TableHead>
<TableRow>
<TableCell>things</TableCell>
<TableCell >date</TableCell>
</TableRow>
</TableHead>
<TableBody>
{userData.map((row,index) => (
<TableRow key={index}>
<TableCell>{row.first}</TableCell>
<TableCell>{row.date}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
Can anyone help me to figure this out ? Thank you.
You can add onClickto handle the click on the row and data-id attribute to store the id value on the row.
<TableRow key={index} onClick={handleRowClick} data-id={row.id}>
<TableCell>{row.first}</TableCell>
<TableCell>{row.date}</TableCell>
</TableRow>
Then you can read the data-id attribute's value in the click handler with
function handleRowClick(e) {
let id = e.currentTarget.getAttribute('data-id')
// Your axios code here
}
Related
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
I have a problem selecting a single checkbox or multiple checkbox in a table in React. I'm using Material-UI. Please see my codesandbox here
CLICK HERE
I wanted to achieve something like this in the picture below:
<TableContainer className={classes.tableContainer}>
<Table>
<TableHead className={classes.tableHead}>
<TableRow>
<TableCell padding="checkbox">
<Checkbox
checked={false}
inputProps={{ "aria-label": "select all desserts" }}
/>
</TableCell>
{head.map((el) => (
<TableCell key={el} align="left">
{el}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{body?.excluded_persons?.map((row, index) => (
<TableRow key={row.id}>
<TableCell padding="checkbox">
<Checkbox checked={true} />
</TableCell>
<TableCell align="left">{row.id}</TableCell>
<TableCell align="left">{row.name}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
Seems you are just missing local component state to track the checked status of each checkbox, including the checkbox in the table header.
Here is the implementation for the AddedPersons component since it's more interesting because it has more than one row of data.
Create state to hold the selected persons state. Only add the additional local state, no need to duplicate the passed body prop data (this is anti-pattern anyway) nor add any derived state, i.e. is indeterminate or is all selected (also anti-pattern).
const [allSelected, setAllSelected] = React.useState(false);
const [selected, setSelected] = React.useState({});
Create handlers to toggle the states.
const toggleAllSelected = () => setAllSelected((t) => !t);
const toggleSelected = (id) => () => {
setSelected((selected) => ({
...selected,
[id]: !selected[id]
}));
};
Use a useEffect hook to toggle all the selected users when the allSelected state is updated.
React.useEffect(() => {
body.persons?.added_persons &&
setSelected(
body.persons.added_persons.reduce(
(selected, { id }) => ({
...selected,
[id]: allSelected
}),
{}
)
);
}, [allSelected, body]);
Compute the selected person count to determine if all users are selected manually or if it is "indeterminate".
const selectedCount = Object.values(selected).filter(Boolean).length;
const isAllSelected = selectedCount === body?.persons?.added_persons?.length;
const isIndeterminate =
selectedCount && selectedCount !== body?.persons?.added_persons?.length;
Attach all the state and callback handlers.
return (
<>
<TableContainer className={classes.tableContainer}>
<Table>
<TableHead className={classes.tableHead}>
<TableRow>
<TableCell colSpan={4}>{selectedCount} selected</TableCell>
</TableRow>
<TableRow>
<TableCell padding="checkbox">
<Checkbox
checked={allSelected || isAllSelected} // <-- all selected
onChange={toggleAllSelected} // <-- toggle state
indeterminate={isIndeterminate} // <-- some selected
inputProps={{ "aria-label": "select all desserts" }}
/>
</TableCell>
...
</TableRow>
</TableHead>
<TableBody>
{body?.persons?.added_persons?.map((row, index) => (
<TableRow key={row.id}>
<TableCell padding="checkbox">
<Checkbox
checked={selected[row.id] || allSelected} // <-- is selected
onChange={toggleSelected(row.id)} // <-- toggle state
/>
</TableCell>
<TableCell align="left">{row.id}</TableCell>
<TableCell align="left">{row.name}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</>
);
Update
Seems there was a bug in my first implementation that disallowed manually deselecting people while the select all checkbox was checked. The fix is to move the logic in the useEffect into the toggleAllSelected handler and use the onChange event to toggle all the correct states. Also to add a check to toggleSelected to deselect "select all" when any person checkboxes have been deselected.
const [allSelected, setAllSelected] = React.useState(false);
const [selected, setSelected] = React.useState({});
const toggleAllSelected = (e) => {
const { checked } = e.target;
setAllSelected(checked);
body?.persons?.added_persons &&
setSelected(
body.persons.added_persons.reduce(
(selected, { id }) => ({
...selected,
[id]: checked
}),
{}
)
);
};
const toggleSelected = (id) => (e) => {
if (!e.target.checked) {
setAllSelected(false);
}
setSelected((selected) => ({
...selected,
[id]: !selected[id]
}));
};
Note: Since both AddedPersons and ExcludedPersons components are basically the same component, i.e. it's a table with same headers and row rendering and selected state, you should refactor these into a single table component and just pass in the row data that is different. This would make your code more DRY.
I have updated your added person table as below,
please note that I am using the component state to update the table state,
const AddedPersons = ({ classes, head, body }) => {
const [addedPersons, setAddedPersons] = useState(
body?.persons?.added_persons.map((person) => ({
...person,
checked: false
}))
);
const [isAllSelected, setAllSelected] = useState(false);
const [isIndeterminate, setIndeterminate] = useState(false);
const onSelectAll = (event) => {
setAllSelected(event.target.checked);
setIndeterminate(false);
setAddedPersons(
addedPersons.map((person) => ({
...person,
checked: event.target.checked
}))
);
};
const onSelect = (event) => {
const index = addedPersons.findIndex(
(person) => person.id === event.target.name
);
// shallow clone
const updatedArray = [...addedPersons];
updatedArray[index].checked = event.target.checked;
setAddedPersons(updatedArray);
// change all select checkbox
if (updatedArray.every((person) => person.checked)) {
setAllSelected(true);
setIndeterminate(false);
} else if (updatedArray.every((person) => !person.checked)) {
setAllSelected(false);
setIndeterminate(false);
} else {
setIndeterminate(true);
}
};
const numSelected = addedPersons.reduce((acc, curr) => {
if (curr.checked) return acc + 1;
return acc;
}, 0);
return (
<>
<Toolbar>
{numSelected > 0 ? (
<Typography color="inherit" variant="subtitle1" component="div">
{numSelected} selected
</Typography>
) : (
<Typography variant="h6" id="tableTitle" component="div">
Added Persons
</Typography>
)}
</Toolbar>
<TableContainer className={classes.tableContainer}>
<Table>
<TableHead className={classes.tableHead}>
<TableRow>
<TableCell padding="checkbox">
<Checkbox
checked={isAllSelected}
inputProps={{ "aria-label": "select all desserts" }}
onChange={onSelectAll}
indeterminate={isIndeterminate}
/>
</TableCell>
{head.map((el) => (
<TableCell key={el} align="left">
{el}
</TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{addedPersons?.map((row, index) => (
<TableRow key={row.id}>
<TableCell padding="checkbox">
<Checkbox
checked={row.checked}
onChange={onSelect}
name={row.id}
/>
</TableCell>
<TableCell align="left">{row.id}</TableCell>
<TableCell align="left">{row.name}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</>
);
};
export default AddedPersons;
Please refer to this for a working example: https://codesandbox.io/s/redux-react-forked-cuy51
Hi All i am building a clone service desk system using React and materialUI I am having issues with removing specific items from an array of objects when the user clicks on it. I have tried to use updatedRow.splice(index,1) but this just removes the last object added to the array and not a specific object. I am trying to remove it based on the ticketID property I have tried to use the array method indexof to console log the specific index of the object but it just returns -1 meaning the item is not in the array when its displaying on the screen. The function should filter and only keep the items which havent been selected based on if the condition is true and remove what is true then should call Setrows to update what is on the screen. Could someone explain exactly what I am doing wrong here see code below...
/// original array to populated with data
let row = [];
const [rows, setRows] = useState(row);
const formDataHandler = ({ desc, option }) => {
const data = {
description: desc,
priority: option,
lastUpdate: Date.now(),
ticketID:shortid.generate()
};
setRows([...rows, data]);
console.log(rows);
};
/// delete row function
const removeTicket = (index)=> {
let updatedRow = rows;
// updatedRow.splice(index,1)
console.log(updatedRow.filter(index => ticketID !== index.id? ))
setRows([...updatedRow])
/// returned
<Container maxWidth="md">
<Grid>
<TableContainer component={Paper}>
<Table className={classes.table} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Description</TableCell>
<TableCell>Priority</TableCell>
<TableCell>Last update</TableCell>
<TableCell>Ticket ID</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.length>0?rows.map((row) => (
<TableRow key={row.ticketID}>
<TableCell component="th" scope="row">
{row.description}
</TableCell>
<TableCell>{row.priority}</TableCell>
<TableCell>{row.lastUpdate}</TableCell>
<TableCell>{row.ticketID}</TableCell>
<TableCell>
<IconButton onClick={removeTicket} aria-label="delete" color="primary">
<DeleteIcon />
</IconButton>
</TableCell>
</TableRow>
)):null}
</TableBody>
</Table>
</TableContainer>
</Grid>
<FormDialog formData={formDataHandler} />
{JSON.stringify(rows)}
</Container>
);
}
You need to pass the ticketID to your IconButton's onClick handler:
<IconButton
onClick={() => removeTicket(row.ticketID)}
aria-label="delete"
color="primary"
>
<DeleteIcon />
</IconButton>
And update your handler where you can create a new array using the .filter() method:
const removeTicket = (ticketID)=> {
setRows(rows.filter(item => ticketID !== item.ticketID)
}
This rows.filter() returns every element where the ticketID is not the same as the one you passed down.
If you know index that will be removed you can use Array.prototype.slice and
the logic is disconsider the element at index.
So, you will have to add the index as second param in your map function and change the onClick on IconButton to () => removeTicket(index).
Your remove function will contains the following snippet:
setRows(prevRows => [
...prevRows.slice(0, index),
...prevRows.slice(index + 1)
]);
If you need the ticketId to make a call to an api you can get it through index rows[index] or by passing it in the onClick function () => removeTicket(row.ticketID, index)
I'm trying to getting this JSON data
{
ID string `json:"id"`
Amount int `json:"amount"`
Month string `json:"month"`
PayFailed bool `json:"pay_failed"`
}
and I wrote my code like this.
but I don't think this code can get data. I did console.log() but nothing come up. so
I don't know how to check to get data successfully.
const Pay = props => {
const { user, month,} = props;
const classes = useStyles();
const [Pay, setPay] = useState([]);
useEffect(() => {
axios
.get(https://test)
.then(res => {
setPay(res.data);
})
.catch(err => {
alert("error");
});
}, [user]);
return (
<Table className={classes.table}>
<TableHead>
<TableRow>
<TableCell >date of pay</TableCell>
<TableCell >amont</TableCell>
<TableCell >pay</TableCell>
</TableRow>
</TableHead>
<TableBody>
{
Pay.filter(pay => pay.month === month).map(pay => (
pay.data.map((pay, index) => (
<TableRow key={index}>
<TableCell>{pay.DeletedAt}</TableCell>
<TableCell>{pay.amount}</TableCell>
<TableCell>{pay.pay_failed}</TableCell>
</TableRow>
)
)))
}
</TableBody>
</Table>
);
};
export default PayDone;
Does anyone know how to get it?
Can you please share some more detail? Like if you are having any errors or what the data looks like in your end, as we don't have access to the exact API. Add a console.log before setPay(res.data); and see what it returns.
Although not important in your case, Why are you doing the nested map? In your JSON schema, there is no object field. Instead all are atomic values.
Pay.filter(pay => pay.month === month).map((pay, index) => (
<TableRow key={index}>
<TableCell>{pay.DeletedAt}</TableCell>
<TableCell>{pay.amount}</TableCell>
<TableCell>{pay.pay_failed}</TableCell>
</TableRow>
))
this feels like a super simple question I thought I knew the solution but just can't figure out why it's not working.
I am trying to display records from Firestore in a table.
Some of the fields go in fine into the table, but one of the fields which is made up of an
array of objects is giving me problems, the object contains childName, childAge & childId. I am trying to display childName.
I just want to display the child name of the first Children object.
but I keep getting the error:
"TypeError: Cannot read property '0' of undefined"
<TableBody>
{forms.map(row => (
<TableRow key={row.id}>
//the TableCell below where I am trying to display childName
<TableCell component={"th"} scope={"row"}>
{row.children[0].childName}
</TableCell>
<TableCell>{row.timeIn}</TableCell>
<TableCell>{row.timeOut}</TableCell>
<TableCell>{row.parentName}</TableCell>
<TableCell>{row.shoeBoxNumber}</TableCell>
</TableRow>
))}
</TableBody>
Below is the full error screenshot:
Below is my state, I'm using React hooks:
Try to add validation: if array is not empty:
{row.children && row.children.length && row.children[0].childName}
<TableBody>
{forms.map(row => (
<TableRow key={row.id}>
//the TableCell below where I am trying to display childName
<TableCell component={"th"} scope={"row"}>
{row.children && row.children.length && row.children[0].childName}
</TableCell>
<TableCell>{row.timeIn}</TableCell>
<TableCell>{row.timeOut}</TableCell>
<TableCell>{row.parentName}</TableCell>
<TableCell>{row.shoeBoxNumber}</TableCell>
</TableRow>
))}
</TableBody>
you can add a validation to check if you array exist with data
<TableBody>
{forms.map((row)=> (
<TableRow key={row.id}>
//the TableCell below where I am trying to display childName
if(row.children[0]){
return (
<TableCell component={"th"} scope={"row"}>
{row.children[0].childName}
</TableCell>
)
}
<TableCell>{row.timeIn}</TableCell>
<TableCell>{row.timeOut}</TableCell>
<TableCell>{row.parentName}</TableCell>
<TableCell>{row.shoeBoxNumber}</TableCell>
</TableRow>
))}
</TableBody>