MUI: The `anchorEl` prop provided to the component is invalid - javascript

I m building a React 18.2 app using MUI 5.10.5, but I have run into a problem creating a <Menu /> element that opens in response to a button click. The menu appears, but it seems the anchorEl is not configured properly, because the menu appears in the top-left of the screen and the browser console has this complaint:
The issue is complicated by the fact that the menus pertain to each row in a <Table /> so, besides anything else, I am not sure if I am supposed to have a single menu outside the table, or repeat the menu for each row in the table. Which seems expensive. But I have organised the code so that the menu is currently duplicated.
export const MetricsQuery = () => {
const [menuState, setMenuState] = useState<{
open: boolean;
anchorEl: null | Element;
}>({open: false, anchorEl: null});
const handleOpenMenuClick = ({currentTarget}: MouseEvent) =>
setMenuState({open: true, anchorEl: currentTarget});
return (
<TableContainer component={Paper}>
<StyledTable>
{/*Header*/}
<TableBody>
{queryMetrics.map((row: QueryMetric) => (
<TableRow>
<TableCell component="th" scope="row">
{row.locationName}
</TableCell>
<TableCell>{row.deviceName}</TableCell>
<TableCell>{row.pointName}</TableCell>
<TableCell>
<Stack>
<IconButton
id="basic-button"
aria-controls={menuState.open ? 'basic-menu' : undefined}
aria-haspopup="true"
aria-expanded={menuState.open ? 'true' : undefined}
onClick={handleOpenMenuClick}
>
<MoreVertIcon sx={{color: theme.palette.primary.light}} fontSize="small"/>
</IconButton>
<Menu
anchorEl={menuState.anchorEl}
open={menuState.open}
onClose={handleClose}
MenuListProps={{
'aria-labelledby': 'basic-button'
}}
>
<MenuItem onClick={handleClose}>Remove</MenuItem>
<MenuItem onClick={handleClose}>Disable</MenuItem>
<MenuItem onClick={handleClose}>Pin to Top</MenuItem>
</Menu>
</Stack>
</TableCell>
</TableRow>
))}
</TableBody>
</StyledTable>
</TableContainer>
)
}
I have tried quite a number of configurations; such as
omitting the ID of the <IconButton />
making this ID unique for each row
having a single menu outside of the <StyledTable />
following the menu documentation more literally
Not sure what else to try..suggestions?

I am not sure if I am supposed to have a single menu outside the table, or repeat the menu for each row in the table.
You can have just one Menu outside of the table. The anchorEl will determine where it is positioned.
You can also have a Menu for every table row, as it will not be rendered to the DOM when it is closed. The advantage of this approach is that each menu can transition independently, so that one can animate closed while another animates open. But if you want to do it this way then you will need a separate menuState for each row, as they all have their own anchors.
What you have right now will open many copies of the same menu, all on top of each other, when any one of the buttons is clicked.
I would move the button and its menu into a new component so that you can have a separate state for each.
const RowMenu = ({ id }: QueryMetric) => {
const [menuState, setMenuState] = useState<{
open: boolean;
anchorEl: null | Element;
}>({ open: false, anchorEl: null });
const handleOpenMenuClick = ({ currentTarget }: { currentTarget: Element }) =>
setMenuState({ open: true, anchorEl: currentTarget });
const handleClose = () => {
setMenuState((prevState) => ({ ...prevState, open: false }));
};
const menuId = `basic-menu-${id}`;
const buttonId = `basic-button-${id}`;
return (
<>
<IconButton
id={buttonId}
aria-controls={menuState.open ? menuId : undefined}
aria-haspopup="true"
aria-expanded={menuState.open ? "true" : undefined}
onClick={handleOpenMenuClick}
sx={{ alignSelf: "center" }}
>
<MoreVertIcon
sx={{ color: (theme) => theme.palette.primary.light }}
fontSize="small"
/>
</IconButton>
<Menu
id={menuId}
anchorEl={menuState.anchorEl}
open={menuState.open}
onClose={handleClose}
MenuListProps={{
"aria-labelledby": buttonId
}}
>
<MenuItem onClick={handleClose}>Remove</MenuItem>
<MenuItem onClick={handleClose}>Disable</MenuItem>
<MenuItem onClick={handleClose}>Pin to Top</MenuItem>
</Menu>
</>
);
};
export const MetricsQuery = () => {
return (
<TableContainer component={Paper}>
<StyledTable>
{/*Header*/}
<TableBody>
{queryMetrics.map((row) => (
<TableRow key={row.id}>
<TableCell component="th" scope="row">
{row.locationName}
</TableCell>
<TableCell>{row.deviceName}</TableCell>
<TableCell>{row.pointName}</TableCell>
<TableCell>
<Stack>
<RowMenu {...row} />
</Stack>
</TableCell>
</TableRow>
))}
</TableBody>
</StyledTable>
</TableContainer>
);
};
CodeSandbox Link
making this ID unique for each row
If you have ids in your DOM then they need to be unique. Your aria attributes don't make sense if they are all the same. But this is a separate issue and I don't think that this would cause any of the issues that you are having with anchor elements.

Related

React function is always called with same parameter in a loop

I have a data array and display its elements in table rows. The last table cell includes a menu item which calls a function with parameter.
The problem is that function handleOpenApproveDialog is always fired with same data element, the last element of myData array.
CodeSandbox link
const handleOpenApproveDialog = (ev, item) => {
setAnchorEl(null);
dispatch(openApproveDialog(item));
//* problem: incoming item parameter is always same. The last element of myData array.
};
<TableBody>
{myData.map((n, i) => {
return (
<TableRow
tabIndex={-1}
key={i}
onClick={(event) => handleRowClick(event, n)}
>
<TableCell className="p-4 md:p-16" component="th" scope="row">
{n.company}
</TableCell>
<TableCell
className="p-4 md:p-16"
component="th"
scope="row"
align="right"
>
<IconButton
aria-label="actions"
id="actions-button"
aria-controls={isMenuOpen ? "actions-menu" : undefined}
aria-expanded={isMenuOpen ? "true" : undefined}
aria-haspopup="true"
onClick={(ev) => {
handleMenuClick(ev);
ev.stopPropagation();
}}
>
<MoreVertIcon />
</IconButton>
<Menu
id="actions-menu"
anchorEl={anchorEl}
open={isMenuOpen}
onClose={handleMenuClose}
>
<MenuItem
onClick={(ev) => {
handleOpenApproveDialog(ev, n);
ev.stopPropagation();
}}
>
Approve
</MenuItem>
</Menu>
</TableCell>
</TableRow>
);
})}
</TableBody>

How do I map over data from API in a collapsible table?

I don't know if the question captures what I had in my but I will explain below...
I fetched data from API and mapped into a collapsible table. Full details of the data should be embedded in EACH row such that onclick on each row, reveals the full details. Here's the code below
function Encounter() {
const [open2, setOpen2] = useState(false);
const [details, setDetails] = useState([]);
const getDetails = async () => {
try {
const fetch = await Axios.get(
"https://pshs3.herokuapp.com/all/encounter"
);
setDetails(fetch.data.data)
} catch (err) {
console.log(err);
}
};
useEffect(() => {
getDetails();
}, []);
return (
<Wrapper>
<Table stickyHeader aria-label="sticky table">
<TableHead>
<TableRow>
<TableCell/>
<TableCell >
Enrollment ID
</TableCell>
<TableCell >
Encounter
</TableCell>
<TableCell>
Facility Code
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{details.map((detail, idx) => {
return (
<>
<TableRow sx={{ "& > *": { borderBottom: "unset" } }}>
<TableCell>
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(!open)}
>
{open ? (
<KeyboardArrowUpIcon />
) : (
<KeyboardArrowDownIcon />
)}
</IconButton>
</TableCell>
<TableCell key={idx}>
{detail.enrollment_id}
</TableCell>
<TableCell key={idx}>
{detail.encounter}
</TableCell>
<TableCell key={idx}>
{detail.faciity_code}
</TableCell>
</TableRow>
<TableRow>
<TableCell
style={{ paddingBottom: 0, paddingTop: 0 }}
colSpan={6}
>
<Collapse in={open} timeout="auto" unmountOnExit>
<Box sx={{ margin: 1 }}>
<Typography variant="h6" gutterBottom component="div">
Details
</Typography>
<Tooltip />
</Box>
</Collapse>
</TableCell>
</TableRow>
</>
);
})}
</TableBody>
</Table>
</Wrapper>
);
}
export default Encounter;
The problem I have is how to implement the open and setOpen state to individual row, also the Tooltip component(which is a the full table details from the API) to display full details of each row onclick which should correspond to the selected row in question.
Here are two solutions to the first problem.
1. Create a separate component for each <TableRow />
This component will have its own state and allows you to collapse/expand each row individually.
2. Use a dictionary for the open state
Since you have multiple (dynamic) rows, you can introduce a dictionary for the open state.
const [open, setOpen] = useState({});
For each row, you will use the open[idx] property to determine if the row should be "open"
<Collapse in={open[idx]} timeout="auto" unmountOnExit>
And in the <IconButton /> component, set the state based on the current row state.
<IconButton
aria-label="expand row"
size="small"
onClick={() => setOpen(current => ({ ...current, [idx]: !current[idx] }))}
>
Firstly add a variable in your details object:
const getDetails = async () => {
try {
const fetch = await Axios.get(
"https://pshs3.herokuapp.com/all/encounter"
);
const response = fetch.data.data;
response.map((elem) => elem.open = false)
setDetails(response)
} catch (err) {
console.log(err);
}
};
Then you can change the open variable for each element in details:
<IconButton
aria-label="expand row"
size="small"
onClick={() => detail.open = !detail.open)}
>
You might need to update the state, so change your onClick:
onClick={() => changeOpenStatus(idx))}
and the function:
const changeOpenStatus = (idx) => {
const newDetails = {...details}
newDetails[idx].open = !newDetails[idx].open;
setDetails(newDetails)
}

Selection Checkbox in React using Hooks

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

Embedding a Menu inside a TableCell with Material-UI

I would like to implement Google's Material UI Menu Item inside of a TableCell, as shown in their docs here, as seen below:
Here is my current approach:
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import {
Grid,
IconButton,
Table,
TableBody,
TableCell,
TableHead,
TableRow,
Paper,
Menu,
MenuItem,
Button,
} from '#material-ui/core';
import { ExpandLess, ExpandMore } from '#material-ui/icons';
const styles = theme => ({});
const Questions = ({ data, classes, openMenu, anchorEls, handleClose }) => {
const CustomTableCell = withStyles(theme => ({
head: {
backgroundColor: theme.palette.common.black,
color: theme.palette.common.white,
},
body: {
fontSize: 14,
},
}))(TableCell);
const formatData = rawData => Object.keys(rawData).map(key => rawData[key]);
const n = { key: 'hi', rating: 55, text: 'wassup' };
return (
<Grid container alignItems={'center'} direction={'column'} spacing={8}>
<Paper className={classes.root}>
<Button
key="close"
aria-label="Close"
color="inherit"
className={classes.close}
onClick={e => openMenu('dude', e)}
>
<ExpandMore />
</Button>
<Menu
id={`dude`}
key="menu"
anchorEl={anchorEls.dude}
open={Boolean(anchorEls.dude)}
onClose={e => handleClose('dude', e)}
>
<MenuItem onClick={e => handleClose('dude', e)}>Delete</MenuItem>
<MenuItem onClick={e => handleClose('dude', e)}>Flag</MenuItem>
<MenuItem onClick={e => handleClose('dude', e)}>
Mark Answered
</MenuItem>
</Menu>
<Table className={classes.table}>
<TableHead>
<TableRow>
<CustomTableCell>Question</CustomTableCell>
<CustomTableCell numeric>Rating</CustomTableCell>
<CustomTableCell>Upvote</CustomTableCell>
<CustomTableCell>Downvote</CustomTableCell>
<CustomTableCell>Options</CustomTableCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow className={classes.row} key={n.key}>
<CustomTableCell component="th" scope="row">
{n.text}
</CustomTableCell>
<CustomTableCell numeric>{n.rating}</CustomTableCell>
<CustomTableCell>
<IconButton
key="close"
aria-label="Close"
color="inherit"
className={classes.close}
onClick={() => ''}
>
<ExpandLess />
</IconButton>
</CustomTableCell>
<CustomTableCell>
<IconButton
key="close"
aria-label="Close"
color="inherit"
className={classes.close}
onClick={() => ''}
>
<ExpandMore />
</IconButton>
</CustomTableCell>
<CustomTableCell>
<Button
key="close"
aria-label="Close"
color="inherit"
className={classes.close}
onClick={e => openMenu(n.key, e)}
>
<ExpandMore />
</Button>
<Menu
id={`simple-menu-${n.key}`}
key="menu"
anchorEl={anchorEls[n.key]}
open={Boolean(anchorEls[n.key])}
onClose={e => handleClose(n.key, e)}
>
<MenuItem onClick={e => handleClose(n.key, e)}>
Delete
</MenuItem>
<MenuItem onClick={e => handleClose(n.key, e)}>dude</MenuItem>
<MenuItem onClick={e => handleClose(n.key, e)}>choc</MenuItem>
</Menu>
</CustomTableCell>
</TableRow>
</TableBody>
</Table>
</Paper>
</Grid>
);
};
Questions.propTypes = {
data: PropTypes.object.isRequired,
anchorEls: PropTypes.object.isRequired,
classes: PropTypes.object.isRequired,
openMenu: PropTypes.func.isRequired,
handleClose: PropTypes.func.isRequired,
};
Questions.defaultProps = {};
export default withStyles(styles)(Questions);
This is working, however the menu is not appearing in the correct place, even when passing in the related event e. I put in a dummy element before the table to test whether or not the table was affecting the menu, and found that the dummy worked just fine, as you can see in the screenshot below.
And the improperly placed menu from the button in the table:
Any ideas on what could be happening? Obviously, the context and anchorEl isn't correctly identifying the location on the page, but not sure what to do to combat that.
Problem in your openMenu function.You need to set the event target in your openMenu function, and set null in handleClose function. I am giving here a little example which may help you:
class DemoList extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
anchorEls: []
}
}
handleActionClick = (id, event) => {
let { anchorEls } = this.state;
anchorEls[id] = event.target;
this.setState({ anchorEls });
}
handleActionClose = (id, event) => {
let { anchorEls } = this.state;
anchorEls[id] = null;
this.setState({ anchorEls });
}
render() {
let { classes } = this.props;
const { data, anchorEls } = this.state;
return (
<Paper className="main">
<Table className={classes.table} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Dessert (100g serving)</TableCell>
<TableCell align="right">Calories</TableCell>
<TableCell align="right">Fat (g)</TableCell>
<TableCell align="right">Carbs (g)</TableCell>
<TableCell align="right">Action</TableCell>
</TableRow>
</TableHead>
<TableBody>
{data.map(row => (
<TableRow key={row.id}>
<TableCell component="th" scope="row"> {row.name} </TableCell>
<TableCell align="right">{row.calories}</TableCell>
<TableCell align="right">{row.fat}</TableCell>
<TableCell align="right">{row.carbs}</TableCell>
<TableCell align="right">
<IconButton
aria-label="more"
aria-controls="long-menu"
aria-haspopup="true"
onClick={e => this.handleActionClick(row.id, e)}
>
<MoreVert />
</IconButton>
<Menu
id={row.id}
anchorEl={anchorEls[row.id]}
keepMounted
open={Boolean(this.state.anchorEls[row.id])}
onClose={e => this.handleActionClose(row.id, e)}
>
<MenuItem onClick={e => this.handleActionClose(row.id, e)}> View Details </MenuItem>
<MenuItem onClick={e => this.handleActionClose(row.id, e)}> Assign </MenuItem>
</Menu>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</Paper>
)
}
}
After hacking away I found that removing the CustomTableCell declaration and changing all the CustomTableCells to normal TableCells resolved the problem. 😫 Not sure why that would fix it given that the CustomTableCell code was pulled straight from the Demos page.

Using Buttons in React Material UI Table

I have made a table using Material UI where I have two buttons in the first column of every row. I wish to edit/delete rows on clicking these but Im stuck on logic. Is it even possible with my implementation ? If not then what's the preferred way of doing so?
render() {
var deleteIcon =
(<IconButton onClick={console.log("delete")}>
<DeleteIcon color="secondary" />
</IconButton>
);
const editIcon = (
<IconButton onClick={console.log("edited")}>
<EditIcon color="primary" />
</IconButton>
);
return(
<TableBody>
{this.state.serviceData.map(n => {
return (
<TableRow key={n.id}>
<TableCell style={styles.editor} component="th" scope="row">
{deleteIcon}
{editIcon}
</TableCell>
<TableCell>{n.domain}</TableCell>
<TableCell>{n.service_name}</TableCell>
</TableCell>
</TableRow>
)};
And my result is :
Building on #st4rl00rd's comment, I was able to tie the buttons using :
const editIcon = (
<IconButton onClick={this.editItem}>
<EditIcon color="primary" />
</IconButton>
);
and binding them in the constructor. I was able to get the selected row data by doing :
<TableBody>
{this.state.serviceData.map(n => {
return (
<TableRow key={n.id} onClick={this.getData.bind(this,n)}>
I have recreated your problem and solved the problem with my logic.
I passed the index of each element as a parameter to the handler functions.
Eg:
const editIcon = index => (
<IconButton onClick={() => this.editComponent(index)}>
<EditIcon color="primary" />
</IconButton>
);
DELETION
For deletion, pass the index as params to the handler function and delete the element at specified index using splice operator.
deleteComponent(index) {
const serviceData = this.state.serviceData.slice();
serviceData.splice(index, 1);
this.setState({ serviceData });
}
EDITING
I have used a state called index to keep track of the index the user is currently editing. Initially the index is -1
So whenever the user clicks edit button the editedIndex is updated.
editComponent(index) {
this.setState({ editedIndex: index });
}
I created two TextField Component which is shown at the specified cell (the cell where editbutton is clicked)
const editDomain = (
<TextField
id="domain"
label="Domain"
className={classes.textField}
value={this.state.editedDomain}
margin="normal"
onChange={this.handleChange('editedDomain')}
/>
);
So Whenever the rendering component Index is equal to editedIndex the editing Compomemts are shown at corresponding Tablecell
<TableCell>
{serviceData.indexOf(n) === editedIndex
? editDomain
: n.domain}
</TableCell>
I suppose you want to do this
I have done same using React-Table here is the link for my project repo you can consider this as an example:
https://github.com/AdnanShah/ReactJS-KretaHub-/blob/Thank_You_Init/src/app/routes/dashboard/routes/Default/rows.js

Categories

Resources