How to edit items inside en Array Input in React admin? - javascript

I have an object that contains objects and each of them has an array of items, I want to attach to each of them an edit button for viewing and deleting In React-admin, but something in my code fails and every time I press the buttons everything gets stuck, you can see in the pictures here:
Thanks!
when I press this buttons the web get stuck:
The buttons in the code:
The Edit part:
The data:
import React from "react";
import {
List,
Datagrid,
TextField,
EmailField,
EditButton,
DeleteButton,
Filter,
TextInput,
ReferenceInput,
SelectInput,
BulkDeleteWithConfirmButton,
DeleteWithConfirmButton,
ArrayField,
ImageField,
ShowButton,
RefreshButton,
CreateButton,
ExportButton,
NumberField,
} from "react-admin";
import { Fragment } from "react";
const UserBulkActionButtons = (props) => (
<Fragment>
<BulkDeleteWithConfirmButton {...props} />
</Fragment>
);
const ShopList = (props) => {
return (
<List
{...props}
filters={<ShopFilter />}
actions={<ProductActionsButtons />}
bulkActionButtons={<UserBulkActionButtons />}
style={{ width: "80%" }}
>
<Datagrid rowClick="show">
<NumberField source="id" />
<TextField source="title" />
<ArrayField source="items">
<Datagrid rowClick="edit">
{" "}
<TextField source="id" />
<TextField source="name" />
<TextField source="description" />
<ImageField source="imageUrl" />{" "}
<NumberField label="in Stock" source="amount" />
<NumberField source="price" />
<ShowButton label="" />
<EditButton />
<DeleteWithConfirmButton />
</Datagrid>
</ArrayField>
<CreateButton />
{/* <EditButton /> */}
</Datagrid>
</List>
);
};
const ShopFilter = (props) => (
<Filter {...props}>
<TextInput label="Search" source="q" alwaysOn />
{/* <ReferenceInput label="Title" source="userId" reference="users" allowEmpty>
<SelectInput optionText="name" />
</ReferenceInput> */}
</Filter>
);
const ProductActionsButtons = (props) => (
<div>
<RefreshButton {...props} />
<CreateButton {...props} />
<ExportButton {...props} />
</div>
);
export default ShopList;
import React from "react";
import {
Edit,
ImageField,
SimpleForm,
TextInput,
Datagrid,
ArrayField,
TextField,
ImageInput,
SimpleFormIterator,
ArrayInput,
Toolbar,
SaveButton,
DeleteWithConfirmButton,
NumberInput,
required,
} from "react-admin";
const ShopEdit = (props) => {
return (
<Edit {...props} title={<ShopTitle />} undoable={false}>
<SimpleForm toolbar={<ProductEditToolbar />}>
<TextInput disabled source="id" />
<TextInput label="Category" source="title" validate={[required()]} />
<ArrayInput source="items">
<SimpleFormIterator>
<TextInput
label="Product Name"
source="name"
validate={[required()]}
/>
<TextInput
label="Product Description"
source="description"
validate={[required()]}
/>
<ImageInput label="Product Image Url" source="imageUrl" />
{/* <TextInput label="Product Price" source="price" /> */}
<NumberInput min="0" step="1" label="in Stock" source="amount" />
<NumberInput
label="Product Price"
min="0.01"
step="0.01"
source="price"
validate={[required()]}
/>
</SimpleFormIterator>
</ArrayInput>
</SimpleForm>
</Edit>
);
};
const ShopTitle = ({ record }) => {
return <span>{record ? `Product "${record.name}"` : ""}</span>;
};
const ProductEditToolbar = (props) => (
<Toolbar {...props}>
<SaveButton />
<DeleteWithConfirmButton />
</Toolbar>
);
export default ShopEdit;

Related

React Formik FieldArray error : A component is changing a controlled input to be uncontrolled

I have a form built with Formik containing an array of objects. When I add a second element to the form with the add-button, I get the following error:
Warning: A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component.
I have made sure that initial values is defined for the the form. I use the FieldArray component from formik. If I remove the time and rate fields, so it's only the name input in each object, I don't get the error, but when I add the time and rate fields, the error occurs. The component contains the following:
const TimeItemsForm = () => {
const jiraItemsStore = useJiraItemsStore();
function jiraTimeImported(timeItemIndex: number, importedHoursTotal: number, checkedItems: CheckedTimeItems) {
// Add checked items to store
jiraItemsStore.setJiraTable(timeItemIndex, checkedItems, importedHoursTotal);
}
const TimeItemSchema = Yup.object().shape({
name: Yup.string().required('Required'),
time: Yup.number().min(0).required('Required'),
// rate: Yup.number().min(0).required('Required'),
});
const TimeItemsSchema = Yup.object().shape({
timeItems: Yup.array().of(TimeItemSchema),
})
const initialValues = {
timeItems: [
{
name: '',
time: 0,
rate: 0,
},
],
};
return (
<>
<Formik
validateOnChange={false}
initialValues={initialValues}
validationSchema={TimeItemsSchema}
onSubmit={(values) => console.log(values)}>
{({ values, errors, touched }) => (
<Form onChange={() => console.log("hs")}>
<FieldArray
name="timeItems"
render={arrayHelpers => (
<div>
{values.timeItems && values.timeItems.length > 0 ? (
values.timeItems.map((timeItem, index) => (
<React.Fragment key={index}>
<Stack gap={2}>
<Flex alignItems="end" gap={4}>
<FormControl>
<FormLabel htmlFor="timeItems[${index}].name">Name</FormLabel>
<Field as={Input} placeholder="Time Item Name" variant="filled" name={`timeItems[${index}].name`} />
</FormControl>
<FormControl>
<FormLabel htmlFor="timeItems[${index}].time">Time</FormLabel>
<InputGroup>
<Field as={Input} type="number" placeholder="0 Hours" variant="filled" name={`timeItems[${index}].time`} />
<InputRightAddon children='Hours' />
</InputGroup>
</FormControl>
<FormControl>
<FormLabel htmlFor="timeItems[${index}].rate">Rate</FormLabel>
<InputGroup>
<Field as={Input} type="number" placeholder="USD 0" variant="filled" name={`timeItems[${index}].rate`} />
<InputRightAddon children='Hours' />
</InputGroup>
</FormControl>
<Flex flexShrink="0" gap={3} direction="column">
<Heading fontWeight="normal" size="sm">Apply Taxes & Discounts</Heading>
<Flex mb={0.5} gap={4}>
<Tooltip label='Tax 1' fontSize='sm'>
<IconButton variant={true ? 'solid' : 'outline'} aria-label='Tax' icon={<TbReceipt />} />
</Tooltip>
<IconButton variant='outline' aria-label='Discount' icon={<TbDiscount />} onClick={() => arrayHelpers.insert(index, { name: "", email: "" })} />
</Flex>
</Flex>
</Flex>
<Flex py={2} gap={10} justifyContent="space-between">
<TimeItemsTable timeItemIndex={index} jiraTimeImported={jiraTimeImported} />
<Flex gap={4}>
<IconButton aria-label='Create Time Item' icon={<MinusIcon />} onClick={() => arrayHelpers.remove(index)} />
<IconButton aria-label='Create Time Item' icon={<AddIcon />} onClick={() => arrayHelpers.insert(index, { name: "", email: "" })} />
</Flex>
</Flex>
</Stack>
<Divider my={4} />
</React.Fragment>
))
) : (
<button type="button" onClick={() => arrayHelpers.push('')}>
Add a Time Item
</button>
)}
<Flex mt={6} gap={10} justifyContent="space-between">
<Button colorScheme="purple" type="submit">Save</Button>
{/* <TimeItemsStats /> */}
</Flex>
</div>
)}
/>
</Form>
)}
</Formik>
</>
)
}
Solution:
The arrayHelpers.push and arrayHelpers.insert didn't insert the values with the correct type, as seen in the code.

How to set custom id for firestore document in react-admin?

I have encountered a problem: How can I set the custom id for the document in the firestore database, as whenever I create a new user firestore is assigning it a random which I cannot figure out.
import * as React from "react";
import {
Datagrid,
List,
Show,
Create,
Edit,
Filter,
SimpleShowLayout,
SimpleForm,
TextField,
TextInput,
ShowButton,
EditButton,
DeleteButton,
} from "react-admin";
import {getAuth} from 'firebase/auth'
const UserFilter = (props) => (
<Filter {...props}>
<TextInput label="Search" source="id_number" alwaysOn />
</Filter>
);
export const UserList = (props) => (
<List {...props} filters={<UserFilter />}>
<Datagrid>
<TextField source="id_number" />
<TextField source="first_name" />
<TextField source="last_name" />
<TextField source="phone" />
<TextField source="user_type" />
<TextField source="email" />
<TextField source="is_active" />
<ShowButton label="" />
<EditButton label="" />
<DeleteButton label="" redirect={false}/>
</Datagrid>
</List>
);
export const UserShow = (props) => (
<Show {...props}>
<SimpleShowLayout>
<TextField source="id" />
<TextField source="first_name" />
<TextField source="user_type" />
<TextField source="email" />
</SimpleShowLayout>
</Show>
);
export const UserCreate = (props) => (
<Create {...props} >
<SimpleForm>
<TextInput source="id_number" />
<TextInput source="first_name" />
<TextInput source="last_name" />
<TextInput source="address" />
<TextInput source="is_active" />
<TextInput source="email" />
<TextInput source="phone" />
<TextInput source="dob" />
<TextInput source="user_type" />
</SimpleForm>
</Create>
);
export const UserEdit = (props) => (
<Edit {...props}>
<SimpleForm>
<TextInput disabled source="id_number" />
<TextInput source="createdate" />
<TextInput source="lastupdate" />
<TextInput source="first_name" />
<TextInput source="user_type" />
<TextInput source="email" />
</SimpleForm>
</Edit>
);
In the create form component how will I set the custom id for my documents?
Before Creating a user, As its prefilled
Firestore database before adding the user
After adding the user
Whenever I create a user, the user is created with a new unique id that is not accessible by us.
As you can in last a document with different is created

how to update parent component when changing child component?

I have two components. A parent component which englobes table of items and an edit component which is opend when only one item is selected to be modified.
this is the parent component:
import * as React from 'react';
import Table from '#mui/material/Table';
import TableBody from '#mui/material/TableBody';
import TableCell from '#mui/material/TableCell';
import TableHead from '#mui/material/TableHead';
import TableRow from '#mui/material/TableRow';
import Title from './Title';
import Grid from '#mui/material/Grid';
import Paper from '#mui/material/Paper';
import Box from '#mui/material/Box';
import Toolbar from '#mui/material/Toolbar';
import Container from '#mui/material/Container';
import { useState, useEffect } from "react";
import ReportDataService from "../services/report";
import FormDialogAdd from "./add-report";
import DeleteDialog from "./delete-report";
import FormDialogEdit from "./edit-report";
const ReportsList = props => {
const [reports, setReports] = useState([]);
// console.log("salut",reports)
const retrieveReports = () => {
ReportDataService.getAll()
.then(response => {
// console.log(response.data);
setReports(response.data.reports);
})
.catch(e => {
console.log(e);
});
};
// update dom after changes were made
useEffect(() => {
retrieveReports();
}, []);
return (
<Box
component="main"
sx={{
backgroundColor: (theme) =>
theme.palette.mode === 'light'
? theme.palette.grey[100]
: theme.palette.grey[900],
flexGrow: 1,
height: '100vh',
overflow: 'auto',
}}
>
<Toolbar />
<Container maxWidth="lg" sx={{ mt: 4, mb: 4 }}>
<Grid container spacing={3}>
{/* Recent Orders */}
<Grid item xs={12}>
<Paper sx={{ p: 2, display: 'flex', flexDirection: 'column' }}>
<React.Fragment>
<Title>Reports</Title>
<Table size="small">
<TableHead>
<TableRow>
<TableCell>name</TableCell>
<TableCell>ecu</TableCell>
<TableCell>category</TableCell>
<TableCell>lastModified</TableCell>
<TableCell>comment</TableCell>
<TableCell>reviewed</TableCell>
</TableRow>
</TableHead>
<TableBody>
{reports.map((report, index) => (
<TableRow key={index}>
<TableCell required>{report.name}</TableCell>
<TableCell>{report.ecu}</TableCell>
<TableCell>{report.category}</TableCell>
<TableCell>{report.lastModified.slice(0,10)}</TableCell>
<TableCell>{report.comment}</TableCell>
<TableCell>{report.reviewd ? "True" : "False"}</TableCell>
<Box sx={{ display: 'flex' }}>
<FormDialogEdit reportId={report._id}/>
<DeleteDialog reportId={report._id} />
</Box>
</TableRow>
))}
</TableBody>
</Table>
</React.Fragment>
</Paper>
<FormDialogAdd/>
</Grid>
</Grid>
</Container>
</Box>
);
};
export default ReportsList;
and this code is for the child component for edit:
import * as React from 'react';
import Button from '#mui/material/Button';
import TextField from '#mui/material/TextField';
import Dialog from '#mui/material/Dialog';
import DialogActions from '#mui/material/DialogActions';
import DialogContent from '#mui/material/DialogContent';
import DialogContentText from '#mui/material/DialogContentText';
import ListItemButton from '#mui/material/ListItemButton';
import FormControlLabel from '#mui/material/FormControlLabel';
import Switch from '#mui/material/Switch';
import ListItemText from '#mui/material/ListItemText';
import DialogTitle from '#mui/material/DialogTitle';
import Fab from '#mui/material/Fab';
import EditIcon from '#mui/icons-material/Edit';
import ReportDataService from "../services/report";
import Box from '#mui/material/Box';
import { useState, useEffect } from "react";
export default function FormDialogEdit(props) {
const [open, setOpen] = React.useState(false);
const handleClose = () => {
setOpen(false);
};
const getSingleReport = (reportId) => {
setOpen(true);
// console.log(reportId)
ReportDataService.get(reportId)
.then(response => {
// console.log("data",response.data);
setReport(response.data);
})
.catch(e => {
console.log(e);
});
};
let initialReportState = ""
const [report, setReport] = useState(initialReportState);
// begins always false=> not convincing param=> should be updated like reviewd
const [manualTest, setManualTest] = React.useState(false);
const handleChangeTestManual = (event) =>{
setManualTest(event.target.checked)
}
const [inputs, setInputs] = useState({});
console.log(inputs);
const handleChange = e => setInputs(prevState => ({ ...prevState, [e.target.name]: e.target.value }));
const handleChangeReviewed= e => setInputs(prevState => ({ ...prevState, [e.target.name]: e.target.checked }));
// console.log("hi",inputs)
const saveReport = () => {
ReportDataService.updateReport(inputs)
.then(response => {
// console.log(response.data);
})
.catch(e => {
console.log(e);
});
};
useEffect(() => {
setInputs(report)
}, [report]);
return (
<div>
<Fab size="small" sx={{ m: 1}} color="primary" aria-label="edit" onClick={() => getSingleReport(props.reportId)}>
<EditIcon />
</Fab>
<Dialog open={open} onClose={handleClose}>
<DialogTitle>Edit report</DialogTitle>
<DialogContent>
<DialogContentText>
You can see here all informations about a report and modify parameters
</DialogContentText>
<Box sx={{ border: 1, borderColor: 'grey.500', borderRadius: 2, marginTop:2}}>
<ListItemButton>
<TextField
autoFocus
margin="dense"
id="name"
label="Name"
name="name"
type="text"
value={inputs.name}
onChange={handleChange}
fullWidth
variant="standard"
/>
</ListItemButton>
<ListItemButton>
<TextField
autoFocus
margin="dense"
id="name"
label="Ecu"
name="ecu"
value={inputs.ecu}
onChange={handleChange}
type="text"
fullWidth
variant="standard"
/>
</ListItemButton>
<ListItemButton>
<TextField
autoFocus
margin="dense"
id="name"
label="Category"
name="category"
value={inputs.category}
onChange={handleChange}
type="text"
fullWidth
variant="standard"
/>
</ListItemButton>
<ListItemButton>
<TextField
autoFocus
margin="dense"
id="name"
label="Comment"
name="comment"
value={inputs.comment}
onChange={handleChange}
type="text"
fullWidth
variant="standard"
/>
</ListItemButton>
<ListItemButton>
<FormControlLabel
control={
<Switch
checked= {manualTest}
onChange={handleChangeTestManual}
/>
}
label="Manual test" />
</ListItemButton>
<ListItemButton>
<FormControlLabel
control={
<Switch
checked= {inputs.reviewd}
name="reviewd"
onChange={handleChangeReviewed}
/>
} label="Reviewed" />
</ListItemButton>
</Box>
<Box sx={{ border: 1, borderColor: 'grey.500', borderRadius: 2, marginTop:2}}>
<ListItemButton>
<ListItemText primary="Last Modified by" secondary={report.lastModifiedBy} />
</ListItemButton>
<ListItemButton>
<ListItemText primary="Last Modified" secondary={report.lastModified} />
</ListItemButton>
<ListItemButton>
<ListItemText primary="Rating" secondary={report.rating} />
</ListItemButton>
<ListItemButton>
<ListItemText primary="Error injection" secondary={report.errorInjection} />
</ListItemButton>
<ListItemButton>
<ListItemText primary="Simulation" secondary={report.simulation} />
</ListItemButton>
<ListItemButton>
<ListItemText primary="Test cases" secondary={report.testCases} />
</ListItemButton>
<ListItemButton>
<ListItemText primary="Last run" secondary={report.lastRun} />
</ListItemButton>
<ListItemButton>
<ListItemText primary="File" secondary={report.file} />
</ListItemButton>
</Box>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Cancel</Button>
<Button onClick={() =>{
saveReport();
handleClose();
}}>
Update</Button>
</DialogActions>
</Dialog>
</div>
);
}
I want to be able to update the parent component when clicking on the update button in the child component. In other world I want the parent component to refresh and modify changes directly. The solution from what i saw is with useEffect but i didn`t know how to use it. So can anyone help? How to notify the parent that a changment has been made so that the table should be updated as soon as the update button in the child is clicked?
Add a props into your child component
like this props.func('updated');
import * as React from 'react';
import Button from '#mui/material/Button';
import TextField from '#mui/material/TextField';
import Dialog from '#mui/material/Dialog';
import DialogActions from '#mui/material/DialogActions';
import DialogContent from '#mui/material/DialogContent';
import DialogContentText from '#mui/material/DialogContentText';
import ListItemButton from '#mui/material/ListItemButton';
import FormControlLabel from '#mui/material/FormControlLabel';
import Switch from '#mui/material/Switch';
import ListItemText from '#mui/material/ListItemText';
import DialogTitle from '#mui/material/DialogTitle';
import Fab from '#mui/material/Fab';
import EditIcon from '#mui/icons-material/Edit';
import ReportDataService from "../services/report";
import Box from '#mui/material/Box';
import { useState, useEffect } from "react";
export default function FormDialogEdit(props) {
props.func('updated');
const [open, setOpen] = React.useState(false);
const handleClose = () => {
setOpen(false);
};
const getSingleReport = (reportId) => {
setOpen(true);
// console.log(reportId)
ReportDataService.get(reportId)
.then(response => {
// console.log("data",response.data);
setReport(response.data);
})
.catch(e => {
console.log(e);
});
};
let initialReportState = ""
const [report, setReport] = useState(initialReportState);
// begins always false=> not convincing param=> should be updated like reviewd
const [manualTest, setManualTest] = React.useState(false);
const handleChangeTestManual = (event) =>{
setManualTest(event.target.checked)
}
const [inputs, setInputs] = useState({});
console.log(inputs);
const handleChange = e => setInputs(prevState => ({ ...prevState, [e.target.name]: e.target.value }));
const handleChangeReviewed= e => setInputs(prevState => ({ ...prevState, [e.target.name]: e.target.checked }));
// console.log("hi",inputs)
const saveReport = () => {
ReportDataService.updateReport(inputs)
.then(response => {
// console.log(response.data);
})
.catch(e => {
console.log(e);
});
};
useEffect(() => {
setInputs(report)
}, [report]);
return (
<div>
<Fab size="small" sx={{ m: 1}} color="primary" aria-label="edit" onClick={() => getSingleReport(props.reportId)}>
<EditIcon />
</Fab>
<Dialog open={open} onClose={handleClose}>
<DialogTitle>Edit report</DialogTitle>
<DialogContent>
<DialogContentText>
You can see here all informations about a report and modify parameters
</DialogContentText>
<Box sx={{ border: 1, borderColor: 'grey.500', borderRadius: 2, marginTop:2}}>
<ListItemButton>
<TextField
autoFocus
margin="dense"
id="name"
label="Name"
name="name"
type="text"
value={inputs.name}
onChange={handleChange}
fullWidth
variant="standard"
/>
</ListItemButton>
<ListItemButton>
<TextField
autoFocus
margin="dense"
id="name"
label="Ecu"
name="ecu"
value={inputs.ecu}
onChange={handleChange}
type="text"
fullWidth
variant="standard"
/>
</ListItemButton>
<ListItemButton>
<TextField
autoFocus
margin="dense"
id="name"
label="Category"
name="category"
value={inputs.category}
onChange={handleChange}
type="text"
fullWidth
variant="standard"
/>
</ListItemButton>
<ListItemButton>
<TextField
autoFocus
margin="dense"
id="name"
label="Comment"
name="comment"
value={inputs.comment}
onChange={handleChange}
type="text"
fullWidth
variant="standard"
/>
</ListItemButton>
<ListItemButton>
<FormControlLabel
control={
<Switch
checked= {manualTest}
onChange={handleChangeTestManual}
/>
}
label="Manual test" />
</ListItemButton>
<ListItemButton>
<FormControlLabel
control={
<Switch
checked= {inputs.reviewd}
name="reviewd"
onChange={handleChangeReviewed}
/>
} label="Reviewed" />
</ListItemButton>
</Box>
<Box sx={{ border: 1, borderColor: 'grey.500', borderRadius: 2, marginTop:2}}>
<ListItemButton>
<ListItemText primary="Last Modified by" secondary={report.lastModifiedBy} />
</ListItemButton>
<ListItemButton>
<ListItemText primary="Last Modified" secondary={report.lastModified} />
</ListItemButton>
<ListItemButton>
<ListItemText primary="Rating" secondary={report.rating} />
</ListItemButton>
<ListItemButton>
<ListItemText primary="Error injection" secondary={report.errorInjection} />
</ListItemButton>
<ListItemButton>
<ListItemText primary="Simulation" secondary={report.simulation} />
</ListItemButton>
<ListItemButton>
<ListItemText primary="Test cases" secondary={report.testCases} />
</ListItemButton>
<ListItemButton>
<ListItemText primary="Last run" secondary={report.lastRun} />
</ListItemButton>
<ListItemButton>
<ListItemText primary="File" secondary={report.file} />
</ListItemButton>
</Box>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Cancel</Button>
<Button onClick={() =>{
saveReport();
handleClose();
}}>
Update</Button>
</DialogActions>
</Dialog>
</div>
);
}
**And in Parent component **
use that props like this
import Container from '#mui/material/Container';
import { useState, useEffect } from "react";
import ReportDataService from "../services/report";
import FormDialogAdd from "./add-report";
import DeleteDialog from "./delete-report";
import FormDialogEdit from "./edit-report";
const ReportsList = props => {
const [reports, setReports] = useState([]);
// console.log("salut",reports)
const retrieveReports = () => {
ReportDataService.getAll()
.then(response => {
// console.log(response.data);
setReports(response.data.reports);
})
.catch(e => {
console.log(e);
});
};
// update dom after changes were made
useEffect(() => {
retrieveReports();
}, []);
return (
<Box
component="main"
sx={{
backgroundColor: (theme) =>
theme.palette.mode === 'light'
? theme.palette.grey[100]
: theme.palette.grey[900],
flexGrow: 1,
height: '100vh',
overflow: 'auto',
}}
>
<Toolbar />
<Container maxWidth="lg" sx={{ mt: 4, mb: 4 }}>
<Grid container spacing={3}>
{/* Recent Orders */}
<Grid item xs={12}>
<Paper sx={{ p: 2, display: 'flex', flexDirection: 'column' }}>
<React.Fragment>
<Title>Reports</Title>
<Table size="small">
<TableHead>
<TableRow>
<TableCell>name</TableCell>
<TableCell>ecu</TableCell>
<TableCell>category</TableCell>
<TableCell>lastModified</TableCell>
<TableCell>comment</TableCell>
<TableCell>reviewed</TableCell>
</TableRow>
</TableHead>
<TableBody>
{reports.map((report, index) => (
<TableRow key={index}>
<TableCell required>{report.name}</TableCell>
<TableCell>{report.ecu}</TableCell>
<TableCell>{report.category}</TableCell>
<TableCell>{report.lastModified.slice(0,10)}</TableCell>
<TableCell>{report.comment}</TableCell>
<TableCell>{report.reviewd ? "True" : "False"}</TableCell>
<Box sx={{ display: 'flex' }}>
<FormDialogEdit reportId={report._id} func={retrieveReports}/>
<DeleteDialog reportId={report._id} />
</Box>
</TableRow>
))}
</TableBody>
</Table>
</React.Fragment>
</Paper>
<FormDialogAdd/>
</Grid>
</Grid>
</Container>
</Box>
);
};
export default ReportsList;
add a new prop to the child component which passes retrieveReports , this can then be called within the child component and the state will update within the parent making it refresh
<FormDialogEdit reportId={report._id} retrieveReports={retrieveReports}/>
Called within child with : props.retrieveReports()

Reactjs TypeError: Cannot read property 'id' of undefined

I facing problem "TypeError: Cannot read property 'id' of undefined" when i using Grid in elements.
the error i facing like this.
Here is my sample code.
In this code only i am facing the issue when im using Grid
<ThemeProvider theme={theme}>
<Card>
<Edit {...props}>
<SimpleForm>
<Grid container spacing={1} align="center">
<Grid item sm={6}>
<ReferenceInput
source="appId"
reference="_apps"
allowEmpty
defaultValue={
props.location.data ? props.location.data.appId : ""
}
validate={required()}
>
<SelectInput optionText="label" />
</ReferenceInput>
</Grid>
<Grid item sm={6}>
<SelectInput
source="iconColor"
choices={[
{ id: "primary", name: "primary" },
{ id: "secondary", name: "secondary" },
{ id: "action", name: "action" },
{ id: "disabled", name: "disabled" },
]}
/>
</Grid>
<Grid item sm={6}>
<ReferenceManyField
label={"resources._fields.name"}
reference="_fields"
target="eid"
>
<Datagrid>
<TextInput type="text" source="label" />
<TextInput type="text" source="component" />
<BooleanField source="showInList" />
<BooleanField source="showInFilter" />
<BooleanField source="showInCreate" />
<BooleanField source="showInEdit" />
<BooleanField source="showInShow" />
<EditButton />
</Datagrid>
</ReferenceManyField>
</Grid>
<Grid item sm={6}>
<ReferenceManyField
label={"resources._triggers.name"}
reference="_triggers"
target="eid"
>
<Datagrid>
<TextInput type="text" source="name" />
<BooleanField source="beforeInsert" />
<BooleanField source="afterInsert" />
<BooleanField source="beforeUpdate" />
<BooleanField source="afterUpdate" />
<BooleanField source="beforeDelete" />
<BooleanField source="afterDelete" />
<EditButton />
</Datagrid>
</ReferenceManyField>
</Grid>
<Grid item sm={6}>
<AddTriggerButton />
<AddFieldButton />
</Grid>
</Grid>
</SimpleForm>
</Edit>
</Card>
</ThemeProvider>
This is my actual code in that screenshot:
const TriggerButton = ({ children, to, ...props }) => {
const CustomLink = React.useMemo(
() =>
React.forwardRef((linkProps, ref) => (
<StyledLink ref={ref} to={to} {...linkProps} />
)),
[to]
);
return (
<Button {...props} component={CustomLink}>
{children}
</Button>
);
};
export default class AddTriggerButton extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false,
props: props,
};
}
render() {
return (
<div>
<TriggerButton
component={Link}
to={{
pathname: "/_triggers/create",
data: { eid: this.state.props.record.id },
}}
startIcon={<AddIcon />}
>
New Trigger
</TriggerButton>
</div>
);
}
}
Because you don't pass any props to AddTriggerButton so props is {}. So this.state.props is {} and this.state.props.record become undefined.
This is not good logic. You need to pass props and use this.props instead this.state.props
<AddTriggerButton record={{id: value}} />
Change this.state.props.record.id to this.props.record.id
Try to console.log(this.state.props.record.id) and shate here the reault. How you defined your the props? Maybe there is an asynchronous problem, so try to put '?' before the id like this:
this.state.props.record?.id

How use dialog in react with materal-iu

i need use a dialog confirmation with react-material-ui, but It doesn't work
this is the error:
Error: MuiThemeProvider.render(): A valid React element (or null) must
be returned. You may have returned undefined, an array or some other
invalid object
This my code:
import React from 'react';
import ReactDom from 'react-dom';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import {Card, CardActions, CardHeader, CardMedia, CardTitle, CardText} from 'material-ui/Card';
import Dialog from 'material-ui/Dialog';
import FlatButton from 'material-ui/FlatButton';
import TextField from 'material-ui/TextField';
import ActionFace from 'material-ui/svg-icons/action/face';
import CommunicationVpnKey from 'material-ui/svg-icons/communication/vpn-key';
const style = {
margin: 5
};
const iconStyles = {
marginRight: 5,
};
export default class DialogExampleSimple extends React.Component {
state = {
open: false,
};
handleOpen = () => {
this.setState({open: true});
};
handleClose = () => {
this.setState({open: false});
console.log(this.context);
};
render() {
const actions = [
<FlatButton
label="Cancel"
primary={true}
onTouchTap={this.handleClose}
/>,
<FlatButton
label="Submit"
primary={true}
keyboardFocused={true}
onTouchTap={this.handleClose}
/>,
];
return (
<div>
<RaisedButton label="Dialog" onTouchTap={this.handleOpen} />
<Dialog
title="Dialog With Actions"
actions={actions}
modal={false}
open={this.state.open}
onRequestClose={this.handleClose}
>
The actions in this window were passed in as an array of React objects.
</Dialog>
</div>
);
}
}
class App extends React.Component {
render() {
return (
<MuiThemeProvider>
<Card shadow={0} style={{width: '550px',margin: 'auto'}}>
<CardMedia
overlay={<CardTitle title="ssa.net" subtitle="Inicio de sesion" />}
>
<img src="{% static 'src/img/ttr.jpg' %}" height="250px" />
</CardMedia>
<CardText>
<div>
<ActionFace style={iconStyles} />
<TextField
hintText="Ingrese su codigo"
floatingLabelText="Codigo de acceso"
fullWidth={false}
/>
</div>
<div>
<CommunicationVpnKey style={iconStyles} />
<TextField
hintText="Ingrese su clave"
floatingLabelText="Clave de acceso"
type="password"
fullWidth={false}
/></div>
</CardText>
<CardActions>
<FlatButton label="Acceder" primary={true} style={style}/>
<FlatButton label="Registro" primary={true} style={style} />
<FlatButton label="Olvide mi acceso" secondary={true} style={style}/>
</CardActions>
</Card>
<DialogExampleSimple />
</MuiThemeProvider>
);
}
}
ReactDom.render(<App/>,document.getElementById('app'));
MuiThemeProvider can have only child, you can not render more than one element, so instead of using MuiThemeProvider in App component, render the main component (App in your case) inside MuiThemeProvider.
Use this:
ReactDom.render(<MuiThemeProvider>
<App/>
<MuiThemeProvider/>,
document.getElementById('app')
);
And remove the <MuiThemeProvider> tag from App component, Use this code for App component:
class App extends React.Component {
render() {
return (
<div>
<Card shadow={0} style={{width: '550px',margin: 'auto'}}>
<CardMedia
overlay={<CardTitle title="ssa.net" subtitle="Inicio de sesion" />}
>
<img src="{% static 'src/img/ttr.jpg' %}" height="250px" />
</CardMedia>
<CardText>
<div>
<ActionFace style={iconStyles} />
<TextField
hintText="Ingrese su codigo"
floatingLabelText="Codigo de acceso"
fullWidth={false}
/>
</div>
<div>
<CommunicationVpnKey style={iconStyles} />
<TextField
hintText="Ingrese su clave"
floatingLabelText="Clave de acceso"
type="password"
fullWidth={false}
/></div>
</CardText>
<CardActions>
<FlatButton label="Acceder" primary={true} style={style}/>
<FlatButton label="Registro" primary={true} style={style} />
<FlatButton label="Olvide mi acceso" secondary={true} style={style}/>
</CardActions>
</Card>
<DialogExampleSimple />
</div>
);
}
}
<MuiThemeProvider> needs to have only one child element, and in your case it has two - a <Card> and a <DialogExampleSimple />.
If you want to render them both, you need to wrap them in a parent component like a <div>

Categories

Resources