Objects are not valid as a React child
(found: object with keys {$$typeof, render, propTypes, Naked, options, useStyles}).
If you meant to render a collection of children, use an array instead.
Code: codesandbox
const Form = () => {
//Input
const [project, setProject] = useState({
id: "",
name: "",
isPublic: false
});
const handleChange = (prop) => (event) => {
setProject({ ...project, [prop]: event.target.value });
};
const handlePermisson = (prop) => (event) => {
setProject({ ...project, [prop]: event.target.checked });
console.log(project);
};
const WithStyles = ({ classes }) => {
return (
<div>
<Grid container>
<Grid item md={6}>
<FormControl
className="classes.bottom-gap"
fullWidth
value={project.id}
onChange={handleChange("id")}
>
<TextField
id="project_id"
label="Project id"
variant="outlined"
/>
</FormControl>
<FormControl
fullWidth
value={project.name}
onChange={handleChange("name")}
>
<TextField
id="project_name"
label="Project name"
variant="outlined"
/>
</FormControl>
<FormControl
fullWidth
value={project.id}
onChange={handlePermisson("isPublic")}
>
<FormControlLabel control={<Switch />} label="Is Public" />
</FormControl>
</Grid>
<Grid item md={6}></Grid>
</Grid>
</div>
);
};
return withStyles(styles)(WithStyles);
};
const styles = {
bottomgap: {
marginBottom: "10px"
}
};
export default Form;
You are attempting to use a higher-order component (HOC) inside of your component. You need to use the HOC outside of the component.
const Form = ({ classes }) => { ...
export default withStyles(styles)(Form);
You are also applying the class name as a literal string className="classes.bottom-gap" rather than applying the actual class name from the classes object. It should be
className={classes.bottomgap}
import React, { useState } from "react";
import {
Grid,
FormControl,
FormControlLabel,
Switch,
TextField
} from "#material-ui/core";
import { withStyles } from "#material-ui/core/styles";
const Form = ({ classes }) => {
//Input
const [project, setProject] = useState({
id: "",
name: "",
isPublic: false
});
const handleChange = (prop) => (event) => {
setProject({ ...project, [prop]: event.target.value });
};
const handlePermisson = (prop) => (event) => {
setProject({ ...project, [prop]: event.target.checked });
console.log(project);
};
return (
<div>
<Grid container>
<Grid item md={6}>
<FormControl
className={classes.bottomgap}
fullWidth
value={project.id}
onChange={handleChange("id")}
>
<TextField
id="project_id"
label="Project id"
variant="outlined"
/>
</FormControl>
<FormControl
fullWidth
value={project.name}
onChange={handleChange("name")}
>
<TextField
id="project_name"
label="Project name"
variant="outlined"
/>
</FormControl>
<FormControl
fullWidth
value={project.id}
onChange={handlePermisson("isPublic")}
>
<FormControlLabel control={<Switch />} label="Is Public" />
</FormControl>
</Grid>
<Grid item md={6}></Grid>
</Grid>
</div>
);
};
const styles = {
bottomgap: {
marginBottom: "10px"
}
};
export default withStyles(styles)(Form);
Related
Assignment details are being fetched and shown in different cards. How can I implement select specific cards feature for getting their data and later on publish those selected cards. I'm putting my code picture and a reference picture.
Reference picture
Actual screen
Code
/* eslint-disable no-unused-vars */
import React, { useEffect, useState } from 'react';
import {
Box, Grid, Typography, IconButton,
} from '#mui/material';
import { useDispatch, useSelector } from 'react-redux';
import { FormikProvider, useFormik } from 'formik';
import { useTranslation } from 'react-i18next';
import AddIcon from '#mui/icons-material/Add';
import DeleteForeverOutlinedIcon from '#mui/icons-material/DeleteForeverOutlined';
import DriveFileRenameOutlineOutlinedIcon from '#mui/icons-material/DriveFileRenameOutlineOutlined';
import RemoveRedEyeOutlinedIcon from '#mui/icons-material/RemoveRedEyeOutlined';
import Card from '#mui/material/Card';
import CardActions from '#mui/material/CardActions';
import CardContent from '#mui/material/CardContent';
import TextField from '#mui/material/TextField';
import { red } from '#mui/material/colors';
import styles from './styles';
import CheckboxAtom from '../../../../components/atoms/checkbox';
import useStyles from '../../../../custom-hooks/useStyles';
import Dropdown from '../../../../components/atoms/dropdown';
import DropdownWithLabel from '../../../../components/atoms/dropdown-with-label';
import ButtonAtom from '../../../../components/atoms/button';
import { Buttons } from '../../../../constant';
import { DialogAtom } from '../../../../components/atoms';
import DatePicker from '../../../../components/atoms/datepicker';
import { getclassesTimings } from '../../../../store/actions/getTeacherView';
import { getClassDetails } from '../../../teacher-user/attendance/helper';
const COURSE_OPTIONS = [
{ id: 'C1', key: 'Course1' },
{ id: 'C2', key: 'Course2' },
{ id: 'C3', key: 'Course3' },
];
const timeElapsed = Date.now();
const today = new Date(timeElapsed);
const CARDS = [
{
id: 'k1',
key: 'Card1',
title: 'ASD',
createdAt: today.toDateString(),
createdBy: 'User1',
questions: [
{
Qname: 'Balabadi-5',
questionBody: [],
},
{
Qname: 'Balabadi 1-Q1',
questionBody: [
'askfhbjksadbnc?', 'askjjkasbcasc?',
],
},
],
},
{
id: 'k2',
key: 'Card2',
title: 'DSDF',
createdAt: today.toDateString(),
createdBy: 'User2',
questions: [
{
Qname: 'Balabadi 1-Q1',
questionBody: [],
},
// {
// Qname: 'Balabadi 1-Q1',
// questionBody: [
// 'askfhbjksadbnc?', 'askjjkasbcasc?',
// ],
// },
],
},
];
// const
const getCurrentAcademicYear = () => {
const currentYear = new Date().getFullYear();
const nextYear = new Date().getFullYear() + 1;
const currentAcademicYear = `${currentYear}-${nextYear}`;
return currentAcademicYear;
};
const getCourseOptions = (courses) => courses.map((course) => ({
id: course.id,
name: course.name,
}));
function OldAssignment({ courses }) {
const classes = useStyles(styles)();
const { t } = useTranslation();
const dispatch = useDispatch();
const reduxClass = useSelector((state) => state?.getTeacherView);
const events = reduxClass?.classesTimings;
const [eventsClassData, setEventsClassData] = useState([]);
const [selectedCourse, setSelectedCourse] = useState('');
const [issetAddAssignmentOpen, setAddAssignmentOpen] = useState(false);
const [ischecked, setIsChecked] = useState(false);
const courseOptions = courses.length ? getCourseOptions(courses) : [];
const handleCheck = (e) => {
setIsChecked(e.target.checked);
};
const onSubmit = (values) => {
// const {
// assignmentId, title, selectEvent, description, selectTopic, defaultScore, scheduledDate, attachResources,
// } = values;
// console.log(values);
// console.log({
// values,
// });
};
const formik = useFormik({
initialValues: {
assignmentId: '',
title: '',
selectEvent: '',
description: '',
selectTopic: '',
defaultScore: '',
scheduledDate: null,
attachResources: null,
},
// eslint-disable-next-line no-undef
onSubmit,
});
const {
touched, handleSubmit, values, errors, setFieldValue, handleChange,
} = formik;
// useEffect(() => {
// console.log(newAssignment);
// console.log(oldAssignment);
// });
useEffect(() => {
if (!selectedCourse) {
return;
}
const payload = {
courseId: selectedCourse,
academicYear: getCurrentAcademicYear(),
};
dispatch(getclassesTimings(payload));
}, [selectedCourse]);
useEffect(() => {
if (!events || !events.length) {
return;
}
setEventsClassData(getClassDetails(events));
}, [events]);
useEffect(() => {
if (!eventsClassData.length) {
return;
}
formik.setFieldValue('selectEvent', eventsClassData[0]?.id || '');
}, [eventsClassData]);
useEffect(() => {
if (!courseOptions || !courseOptions.length) {
return;
}
setSelectedCourse(courseOptions[0]?.id || '');
}, [courseOptions]);
// const handleSubmit = (values) => {
// return ({
// console,: .log(values)
// });
// }
const renderAddFolderContent = () => (
<Grid className={classes.addDialog}>
<FormikProvider value={formik}>
<Box
component="form"
sx={{
'& .MuiTextField-root': { m: 1, width: '10vw' },
}}
noValidate
autoComplete="off"
>
<Grid container spacing={2} sx={{ display: 'flex' }}>
<Grid item>
<TextField
className={classes.popupTextField}
required
id="outlined-required"
label="Assignment Id"
// value={isAddFolderName}
// onChange={(e) => setAddFolderName(e.target.value)}
defaultValue={formik.values.assignmentId}
name="assignmentId"
// onChange={(e) => setFieldValue('assignmentId', e.target.value)}
onChange={formik.handleChange}
/>
</Grid>
<Grid item>
<TextField
className={classes.popupTextField}
required
id="outlined-required"
label="Title"
// value={isAddFolderName}
// onChange={(e) => setAddFolderName(e.target.value)}
name="title"
value={formik.values.title}
onChange={formik.handleChange}
/>
</Grid>
<Grid item sx={{ minWidth: '13vw' }}>
<DropdownWithLabel
id="selectEvent"
name="selectEvent"
disabled={false}
options={eventsClassData}
// label={`${t('COURSES')}`}
label="Select Event"
placeholder="Select Event"
customStyles={classes.dropDownCont}
handleChange={formik.handleChange}
value={formik.values.selectEvent}
/>
</Grid>
<Grid item>
<TextField
className={classes.popupTextField}
required
id="outlined-required"
label="Description"
name="description"
// value={isAddFolderName}
// onChange={(e) => setAddFolderName(e.target.value)}
defaultValue={formik.values.description}
value={formik.values.description}
onChange={formik.handleChange}
/>
</Grid>
</Grid>
<Grid container spacing={2} sx={{ display: 'flex', marginTop: '10px' }}>
<Grid item sx={{ minWidth: '13vw' }}>
<DropdownWithLabel
id="selectTopic"
name="selectTopic"
disabled={false}
options={
COURSE_OPTIONS.map((course) => ({
id: course.id,
name: course.key,
}))
}
// label={`${t('COURSES')}`}
label="Select Topic"
handleChange={formik.handleChange}
value={formik.values.selectTopic}
/>
</Grid>
<Grid item>
<TextField
className={classes.popupTextField}
required
id="outlined-required"
label="Default Score"
name="defaultScore"
// value={isAddFolderName}
// onChange={(e) => setAddFolderName(e.target.value)}
defaultValue={formik.values.defaultScore}
onChange={formik.handleChange}
/>
</Grid>
<Grid item>
<div className={classes.datePickerWrapper}>
<DatePicker
style={{ padding: '0px !important' }}
required
/>
</div>
</Grid>
<Grid item>
<TextField
className={classes.popupTextField}
required
id="outlined-required"
label="Attach Resources"
// value={isAddFolderName}
// onChange={(e) => setAddFolderName(e.target.value)}
defaultValue={formik.values.attachResources}
name="attachResources"
/>
</Grid>
</Grid>
</Box>
<Grid item xs={12} sx={{ display: 'flex', justifyContent: 'flex-end', marginTop: '10px' }}>
<ButtonAtom
className={classes.popupBtn}
name={t('CANCEL')}
// onClick={() => setAddFolderOpenDialog(false)}
btntype={Buttons.SECONDARY}
/>
<ButtonAtom
className={classes.popupBtn}
name={t('ADD')}
btntype={Buttons.PRIMARY}
type="submit"
// onclick={() => console.log('skjbdaskjhbd')}
onClick={handleSubmit}
/>
</Grid>
</FormikProvider>
</Grid>
);
return (
<Box container>
<DialogAtom
isOpen={issetAddAssignmentOpen}
dialogHeading={t('ADD_ASSIGNMENT')}
customClass={classes.DialogAtom}
content={renderAddFolderContent()}
secHandle={() => setAddAssignmentOpen(false)}
/>
<Box className={classes.topContainerBox}>
<Grid item className={classes.headerGridItem}>
<div>
<Typography className={classes.headerTitle}>
{t('OLD_ASSIGNMENT')}
</Typography>
</div>
</Grid>
<Grid item className={classes.functionalGridItem}>
<div className={classes.dropdownDiv}>
{/* <DropdownWithLabel
id="courses"
name="courses"
disabled={false}
options={courseOptions}
label={`${t('COURSES')}`}
placeholder="COURSES"
customStyles={classes.dropDownCont}
value={selectedCourse}
handleChange={(e) => {
const { val } = e.target;
setSelectedCourse(val);
}}
/> */}
<ButtonAtom
className={classes.popupBtn}
name={t('CANCEL')}
// onClick={() => setAddFolderOpenDialog(false)}
btntype={Buttons.SECONDARY}
/>
</div>
<div className={classes.buttonDiv}>
<ButtonAtom
name={t('PUBLISH')}
onClick={() => { setAddAssignmentOpen(true); }}
btntype={Buttons.PRIMARY}
// icon={<AddIcon />}
/>
</div>
</Grid>
</Box>
<Box>
<Grid container spacing={2} className={classes.bottomGridContainer}>
{
CARDS.map((card) => {
return (
<Grid item>
<Card className={classes.mainCard}>
<Box className={classes.cardContainerBox}>
<Box className={classes.cardTopBox}>
<Grid
container
className={classes.firstGridContainer}
>
<Grid item>
<CardContent className={classes.zeroPadding}>
<Typography className={classes.cardTitleContainer}>
{card.title}
</Typography>
</CardContent>
</Grid>
<Grid item>
<Grid item>
<CardActions disableSpacing className={classes.zeroPadding}>
<CheckboxAtom
checked={ischecked}
handleChange={(e) => console.log(card.title)}
label=""
/>
</CardActions>
</Grid>
<Grid item />
</Grid>
</Grid>
<Grid conatiner className={classes.secondGridContainer}>
<CardContent className={classes.zeroPadding}>
<Typography variant="caption">
{card.createdAt}
</Typography>
</CardContent>
</Grid>
{/* <Grid
container
className={classes.thirdGridContainer}
>
<Grid item>
<CardContent className={classes.zeroPadding}>
<Typography variant="caption">
{card.createdBy}
</Typography>
</CardContent>
</Grid>
<Grid item>
<CardActions disableSpacing className={classes.zeroPadding}>
<IconButton aria-label="add to favorites" className={classes.zeroPadding}>
<RemoveRedEyeOutlinedIcon color="primary" />
</IconButton>
</CardActions>
</Grid>
</Grid> */}
</Box>
<hr />
<Box className={classes.cardBottomBox}>
{
card.questions.map((q) => {
return (
<Grid Conatiner className={classes.cardBottomGridContainer}>{q.Qname}</Grid>
);
})
}
</Box>
</Box>
</Card>
</Grid>
);
})
}
</Grid>
</Box>
</Box>
);
}
export default OldAssignment;
There are a lot of unnecessary code please ignore those, this is still under development.
<CheckboxAtom
checked={ischecked}
handleChange={(e) => console.log(card.title)}
label=""
/>
This is the checkbox.
I'm using Material UI to create an application with React. I have a Dialog that allows the user to change a series of information about an object (see the code below). There are two different buttons. Each button refers to a different object. So, depending on which object the user wants to change, the onDialogOpen function is called with different parameters. Everything is working fine.
export default function CollectingFormInput() {
const [dialogOpen, setDialogOpen] = useState(false);
const [snackbarOpen, setSnackbarOpen] = useState(false);
const [snackbarMessage, setSnackbarMessage] = useState('');
const [name, setName] = useState("");
const [alias, setAlias] = useState("");
const [latitude, setLatitude] = useState("");
const [longitude, setLongitude] = useState("");
const [address, setAddress] = useState("");
const [notes, setNotes] = useState("");
const onDialogOpen = (info) => {
setName(info.name);
setAlias(info.alias);
setLatitude(info.latitude);
setLongitude(info.longitude);
setAddress(info.address);
setNotes(info.notes);
setDialogOpen(true);
};
const onDialogClose = () => {
setDialogOpen(false);
};
const onSnackbarClose = (e, reason) => {
if (reason === 'clickaway') {
return;
}
setSnackbarOpen(false);
setSnackbarMessage('');
};
const onCreate = () => {
setSnackbarOpen(true);
setSnackbarMessage(`Dados de ${name} atualizados!`);
onDialogClose();
};
return (
<Fragment>
<Button color="primary" onClick={()=> onDialogOpen({
name: "JAF_01",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})}>
Botão 1
</Button>
<Button color="primary" onClick={()=> onDialogOpen({
name: "JAF_02",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})}>
Botão 2
</Button>
<Dialog open={dialogOpen} onClose={onDialogClose}>
<DialogTitle>Editar informações da estação</DialogTitle>
<DialogContent>
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<TextField
margin="normal"
id="station-name"
id="outlined-read-only-input"
label="Nome"
defaultValue={name}
size="small" fullWidth
InputProps={{
readOnly: true,
}}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
margin="normal"
id="station-alias"
id="outlined-basic"
label="Apelido"
InputProps={{ name: 'alias' }}
onChange={field => setAlias(field.target.value)}
value={alias}
defaultValue=""
size="small" fullWidth
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
margin="normal"
id="station-latitude"
id="outlined-basic"
label="Latitude"
InputProps={{ name: 'latitude' }}
onChange={field => setLatitude(field.target.value)}
value={latitude}
defaultValue=""
size="small"
fullWidth
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
margin="normal"
id="station-longitude"
id="outlined-basic"
label="Longitude"
InputProps={{ name: 'longitude' }}
onChange={field => setLongitude(field.target.value)}
value={longitude}
defaultValue=""
size="small"
fullWidth
/>
</Grid>
</Grid>
<TextField
margin="normal"
id="station-address"
id="outlined-basic"
label="Endereço"
InputProps={{ name: 'address' }}
onChange={field => setAddress(field.target.value)}
value={address}
defaultValue=""
size="small"
fullWidth
/>
<TextField
margin="normal"
id="station-obs"
id="outlined-multiline-flexible"
multiline
maxRows={4}
label="Observações"
InputProps={{ name: 'notes' }}
onChange={field => setNotes(field.target.value)}
value={notes}
defaultValue=""
size="small"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={onDialogClose} color="primary">Cancelar</Button>
<Button
variant="contained"
onClick={onCreate}
color="primary"
>
Salvar
</Button>
</DialogActions>
</Dialog>
<Snackbar
open={snackbarOpen}
message={snackbarMessage}
onClose={onSnackbarClose}
autoHideDuration={4000}
/>
</Fragment>
);
}
Now, I'd like to clean up the code and create a new CollectingFormInput component that is independent of the two buttons. So my code would be something like...
<Fragment>
<Button color="primary" onClick={()=> onDialogOpen({
name: "JAF_01",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})}>
Botão 1
</Button>
<Button color="primary" onClick={()=> onDialogOpen({
name: "JAF_02",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})}>
Botão 2
</Button>
<CollectingFormInput />
<Fragment>
I think that onDialogOpen would have to belong to the CollectingFormInput component and be called by the parent component.
I searched but couldn't find a way to access onDialogOpen from the parent component. Can someone help me?
You can use useImperativeHanlde hook and forwardRef hook to expose some methods in a child component to a parent component.
Wrap the CollectingFormInput in a forwardRef. And use useImperativeHanlde hook to expose methods in it as below.
import { forwardRef, useImperativeHandle } from "react";
const CollectingFormInput = forwardRef((props, ref) => {
...
...
...
const onDialogOpen = (info) => {
setName(info.name);
setAlias(info.alias);
setLatitude(info.latitude);
setLongitude(info.longitude);
setAddress(info.address);
setNotes(info.notes);
setDialogOpen(true);
};
const onDialogClose = () => {
setDialogOpen(false);
};
useImperativeHandle(ref, () => ({
onDialogOpen: onDialogOpen,
onDialogClose: onDialogClose
}));
...
...
return (
...
...
);
});
In the parent component create a ref and pass it to CollectingFormInput to get initialized with the functions you exposed there in the component. Call the methods after doing the null / undefined checking.
import { useRef } from "react";
const ParentComp = () => {
const dialogHandleRef = useRef(null);
return (
<Fragment>
<Button
color="primary"
onClick={() =>
dialogHandleRef &&
dialogHandleRef?.current?.onDialogOpen({
name: "JAF_01",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})
}
>
Botão 1
</Button>
<Button
color="primary"
onClick={() =>
dialogHandleRef &&
dialogHandleRef?.current?.onDialogOpen({
name: "JAF_02",
alias: "",
latitude: 0,
longitude: 0,
address: "",
notes: ""
})
}
>
Botão 2
</Button>
<CollectingFormInput ref={dialogHandleRef} />
</Fragment>
);
};
I am trying to create a form and store it in an useState array, every time there is a change on "maritalStatus" of the field and the status is 'Married' - I need to append the form so that the data I will store will store 2 persons details from the form (firstname/lastname/phone etc) if the status is other than 'Married' the data I store will only be for 1 person.
I am new to RN and I just can't handle this "IF" condition, would be glad if anyone can help.
Also in case the person selects - the children field and inputs a value( for example 2) the array should also be appended with 2 other fields and I will add later a fuction that will store this data on a remote server.
import React, { useState } from "react";
import {
Card,
CardContent,
Container,
Grid,
TextField,
FormControl,
InputLabel,
MenuItem,
Select,
FormControlLabel,
RadioGroup,
Radio,
FormLabel
} from '#mui/material';
import { Box } from '#mui/system';
function AddForm() {
const defaultData = {
firstName: '',
lastName:'',
email:'',
childrens:'',
gender:'Male',
participation:'Yes',
phone1:'',
phone2:'',
phone3:'',
maritalStatus:'',
}
const [applicant, setApplicant] = useState([{ ...defaultData }]);
const onChange = (e, index) => {
const { name, value } = e.target;
const data = [...applicant];
data[index][name] = value;
setApplicant(data);
};
const onChildrensChange = (e, index) => {
const { name, value } = e.target;
const data = [...applicant];
data[index][name] = value;
setApplicant(data)
setApplicant([...applicant, { ...defaultData }]);
};
let onMaritalStatusChange = (e, index) => {
const { name, value } = e.target;
const data = [...applicant];
data[index][name] = value;
setApplicant(data)
if(e.maritalStatus === 'Married'){
setApplicant([...applicant, { ...defaultData }]);
}
};
const onAddClick = () => {
setApplicant([...applicant, { ...defaultData }]);
};
return (
<Container>
<Card>
<CardContent>
{applicant.map((element, index) => {
return (
<Grid>
<Grid>
<TextField
label="First Name"
name="firstName"
value={element.firstName}
onChange={(e) => onChange(e, index)}
fullWidth
/>
<TextField
label="Last name"
name="lastName"
value={element.lastName}
onChange={(e) => onChange(e, index)}
fullWidth
/>
<TextField
label="Email"
name="email"
value={element.email}
onChange={(e) => onChange(e, index)}
fullWidth
/>
<TextField
label="childrens"
name="childrens"
value={element.childrens}
onChange={(e) => onChildrensChange(e, index)}
fullWidth
/>
<FormControl fullWidth>
<InputLabel>Gender</InputLabel>
<Select
label="gender"
name='gender'
fullWidth
onChange={(e) => onChange(e, index)}
defaultValue='Male'
>
<MenuItem value={'Male'}>Male</MenuItem>
<MenuItem value={'Female'}>Female</MenuItem>
</Select>
</FormControl>
<FormControl fullWidth>
<InputLabel>Marital Status</InputLabel>
<Select
label="maritalStatus"
name='maritalStatus'
fullWidth
onChange={(e) => onMaritalStatusChange(e, index)}
defaultValue='Single'
>
<MenuItem value={'SINGLE'}>Single</MenuItem>
<MenuItem value={'Married'}>Married</MenuItem>
<MenuItem value={'Divorced'}>Divorced</MenuItem>
<MenuItem value={'Widowed'}>Widowed</MenuItem>
</Select>
</FormControl>
<FormControl>
<FormLabel>Participation</FormLabel>
<RadioGroup
defaultValue="female"
name="participation"
onChange={(e) => onChange(e, index)}
>
<FormControlLabel value="Yes" control={<Radio />} label="Yes" />
<FormControlLabel value="No" control={<Radio />} label="No" />
</RadioGroup>
</FormControl>
<TextField
label="Phone"
name="phone1"
value={element.phone1}
onChange={(e) => onChange(e, index)}
fullWidth
/>
<TextField
label="Phone"
name="phone2"
value={element.phone2}
onChange={(e) => onChange(e, index)}
fullWidth
/>
<TextField
label="Phone"
name="phone3"
value={element.phone3}
onChange={(e) => onChange(e, index)}
fullWidth
/>
</Grid>
</Grid>
)
})}
<Box mt={5}>{JSON.stringify(applicant)}</Box>
</CardContent>
</Card>
</Container>
)
}
export default AddForm;
import './App.css';
import AddForm from './AddForm';
function App() {
return (
<div className="App">
<AddForm/>
</div>
);
}
export default App;
Define a key like "spouse" with object type value on defaultData object.
Have the spouse form details defined just beneath the "maritalStatus" select dropdown.
Use conditional rendering for spouse form like below
{ element.maritalStatus === "Married" && (
// write the spouse form here
)}
So, as soon as you update the state with maritalStatus and it is "Married", the spouse form details would be rendered.
You can do the same for children forms too.
You are checking e. maritalStatus. Instead you should check e.target.value or, in your case, as you are already destructuring the value, you can directly check the value
if(value==="Married"){ // write your code over here}
Also to solve this problem you need to play with the Applicant state where on the basis of children and married you can show the form.
const Myform = () => {
const defaultData = {
firstName: "",
lastName: "",
email: "",
childrens: "",
gender: "Male",
participation: "Yes",
phone1: "",
phone2: "",
phone3: "",
maritalStatus: ""
};
const [applicant, setApplicant] = React.useState(defaultData);
const handleChildern = (e) => {
const udatedApplicant = { ...applicant };
udatedApplicant.childrens = e.target.value;
setApplicant({ ...udatedApplicant });
};
const handleRadio = (e) => {
const udatedApplicant = { ...applicant };
udatedApplicant.maritalStatus = e.target.value;
setApplicant({ ...udatedApplicant });
};
return (
<>
<div onChange={handleRadio}>
<label htmlFor="Married">Married</label>
<input type="radio" id="Married" name="marStatus" value="Married" />
<label htmlFor="single">Single</label>
<input type="radio" id="single" name="marStatus" value="Single" />
</div>
<div>
<label htmlFor="children">children</label>
<input type="text" id="children" onChange={handleChildern} />
</div>
{applicant.maritalStatus === "Married" && <RenderSpouse />}
{Number(applicant.childrens) > 0 && (
<RenderChildren numberOfChildren={applicant.childrens} />
)}
</>
);
};
const RenderSpouse = () => {
return <div>Hi I am spouse</div>;
};
const RenderChildren = ({ numberOfChildren }) => {
const [childrens, setChildrens] = React.useState(
new Array(Number(numberOfChildren)).fill("")
);
useEffect(() => {
const newChildren = new Array(Number(numberOfChildren)).fill("");
setChildrens(newChildren);
}, [numberOfChildren]);
return (
<>
{childrens.map((_, index) => {
return <div key={index}>children {index}</div>;
})}
</>
);
};
So with this approach your form would be more generic to solve this problem
Working Code Example
I'm trying to bind to a nested array to text inputs from a form. There are 6 blocks and each block contains 3 values. I have initially populated the array for mapping by using:
new Array(6).fill(['','',''])
and rendering the values using 2 loops. One for the 6 blocks and the other 3 values inside each block. The 3 values are the ones binding to the form. I refer to each of the inputs using the second parameter of the map function which is the index.
Here is the code in its entirety.
import {
Card,
CardContent,
CardHeader,
CardMedia,
TextField,
Grid,
Typography,
Button,
} from "#material-ui/core";
import axios from "axios";
import { useState } from "react";
import { useHistory } from "react-router";
export default function CreateEditQuestion() {
const answerPack = new Array(6).fill(["", "", ""]);
const [question, setQuestion] = useState("");
const [answers, setAnswer] = useState(answerPack);
const [TimeAllowed, setTimeAllowed] = useState(30);
const [Score, setScore] = useState(1);
const [Date, setDate] = useState("");
const history = useHistory();
const handleAnswerSet = (value, answerIndex, answerTextIndex) => {
var updatedAnswer = answers;
updatedAnswer[answerIndex][answerTextIndex] = value;
setAnswer(updatedAnswer);
};
const handleSubmit = () => {
let data = {
question,
answer_set: answers,
time_allowed: TimeAllowed,
score_value: Score,
date: Date,
};
for (const [key, value] of Object.entries({ question, Date })) {
if (value.trim().length == 0) {
alert(`${key} has not been filled in`);
return false;
}
}
axios
.post(
"https://localhost:8000/question",
data
)
.then((resp) => {
alert("Succesfully added Question");
history.push("/question");
})
.catch((err) => {
console.log(err);
});
};
return (
<>
<h1>Create Question</h1>
<Card elevation={1}>
<CardHeader></CardHeader>
<CardContent>
<div>
<TextField
fullWidth
label="Question"
variant="outlined"
onChange={(e) => {
setQuestion(e.target.value);
}}
></TextField>
</div>
<Grid container direction={"row"} spacing={4}>
{answers.map((answerTexts, i) => {
return (
<Grid key={i} item md={4} width={50}>
{answerTexts.map((text, j) => {
return (
<div style={{ width: "70%", marginTop: "30px" }}>
<TextField
fullWidth
label={`Answer ${i + 1} - ${j + 1}`}
onChange={(ev) => {
handleAnswerSet(ev.target.value, i, j);
}}
variant="outlined"
/>
<br />
</div>
);
})}
</Grid>
);
})}
</Grid>
<Grid container direction={"row"} spacing={4}>
<Grid item md={5} width={80}>
<Typography variant="h6" gutterBottom gutterTop>
Extra Options
</Typography>
<TextField
label={"Time Allowed : "}
variant="outlined"
defaultValue={TimeAllowed}
onChange={(ev) => {
setTimeAllowed(ev.target.value);
}}
/>{" "}
<TextField
label="Score"
variant="outlined"
defaultValue={Score}
onChange={(ev) => {
setScore(ev.target.value);
}}
/>
</Grid>
<Grid item md={5} width={100}>
<Typography variant="h6" gutterBottom gutterTop>
Question Date
</Typography>
<TextField
type="date"
onChange={(ev) => {
setDate(ev.target.value);
}}
/>
</Grid>
</Grid>
<div align="center">
<Button
onClick={() => {
handleSubmit();
}}
variant="contained"
color="primary"
>
Submit Question
</Button>
</div>
</CardContent>
</Card>
</>
);
}
Problem:
On each block, changing any value also changes all the other corresponding inputs in other blocks, so if the first input on the first block is changed, then all other first inputs in the other blocks also get changed,e.g(changing answer 1-1 also changes 2-1,3-1,4-1, etc). I could not trace why. Only the corresponding values should be changed
This is the function responsible for setting the values.
const handleAnswerSet = (value, answerIndex, answerTextIndex) => {
var updatedAnswer = answers;
updatedAnswer[answerIndex][answerTextIndex] = value;
setAnswer(updatedAnswer);
};
I'm using the Select component on #material-ui/core, but I'm having the following problem:
Cannot read property 'offsetWidth' of null
Can you help me out?
Link: codesandbox
Code:
import React from "react";
import {
Button,
DialogTitle,
Dialog,
DialogContent,
DialogActions,
TextField,
FormControl,
InputLabel,
MenuItem,
Select
} from "#material-ui/core";
function AddUserModal(props) {
const inputLabelTypeRole = React.useRef(null);
const { open, onClose } = props;
const [state, setState] = React.useState({
labelWidthTypeRole: 0,
name: ""
});
let { labelWidthTypeRole } = state;
React.useEffect(() => {
setState({
...state,
labelWidthTypeRole: inputLabelTypeRole.current.offsetWidth
});
}, []);
const onChange = name => ({ target: { value } }) => {
setState({
...state,
[name]: value
});
};
const [currency, setCurrency] = React.useState(false);
const handleChange = event => {
setCurrency(event.target.value);
};
return (
<Dialog
fullWidth
maxWidth="md"
open={open}
onClose={onClose}
aria-labelledby="max-width-dialog-title"
>
<DialogTitle id="form-dialog-title" style={{ alignSelf: "center" }}>
Add User
</DialogTitle>
<DialogContent>
<div style={{ margin: 5 }}>
<TextField
margin="dense"
id="name"
label="Name"
type="Name"
fullWidth
variant="outlined"
onChange={onChange("name")}
/>
</div>
<div style={{ margin: 5 }}>
<FormControl variant="outlined" fullWidth size="small">
<InputLabel
ref={inputLabelTypeRole}
id="demo-simple-select-outlined-label"
>
Role
</InputLabel>
<Select
labelId="demo-simple-select-outlined-label"
id="demo-simple-select-outlined"
labelWidth={labelWidthTypeRole}
value={false}
>
<MenuItem value={false}>Report</MenuItem>
<MenuItem value>Report Web hook</MenuItem>
</Select>
</FormControl>
</div>
<div style={{ margin: 5 }}>
<TextField
id="outlined-select-currency"
select
label="Select"
helperText="Please select your currency"
variant="outlined"
fullWidth
value={currency}
onChange={handleChange}
>
<MenuItem value={false}>Report</MenuItem>
<MenuItem value>Report Web hook</MenuItem>
</TextField>
</div>
</DialogContent>
<DialogActions>
<Button onClick={onClose} color="primary" variant="contained">
Create
</Button>
</DialogActions>
</Dialog>
);
}
export default function App() {
const [open, setOpen] = React.useState(false);
return (
<div className="App">
<AddUserModal open={open} onClose={() => setOpen(false)} />
<button onClick={() => setOpen(true)}>Open</button>
</div>
);
}
The error is resolved very simply: remove "current" in useEffect hook:
React.useEffect(() => {
setState({
...state,
labelWidthTypeRole: inputLabelTypeRole.**current**.offsetWidth
});
}, []);
Because in the example that you used there are several components, but you have one component and "current" is superfluous.