Get value from few Select in Material-UI - javascript

I have two MUI Select components on my page. I'm trying to set values depends on id of Select. I've checked (id === "breed-select") in console and (at first) it's true, but immediately after that it become false, and i cant understand why. Where i made a mistake? May be there is a better way to set values of two Select components? CodeSandbox
import React from 'react';
import './AddCatPopup.css';
import {Box, Button, FormControl, InputLabel, MenuItem, Select, TextField} from '#mui/material';
import {theme} from '../../theme';
import {ThemeProvider} from '#mui/material/styles';
function AddCatPopup({ breeds, isOpen, onClose, onAddCat }) {
const breedsName = breeds.map(item => item.nameBreed);
const colorsArray = [
'black',
'white',
'grey',
'red',
'multicolor'
];
const [name, setName] = React.useState('');
const [price, setPrice] = React.useState(0);
const [color, setColor] = React.useState('');
const [age, setAge] = React.useState(0);
const [breed, setBreed] = React.useState('');
function handleChange(event) {
const {
target: { value, id }
} = event;
id === "breed-select" ? setBreed(value) : setColor(value);
}
function handleSubmit(e) {
e.preventDefault();
}
return(
<section className={`popup ${isOpen && 'popup_opened'}`}>
<div className={'popup__container'}>
<button type="button" className={'popup__close-btn'} onClick={onClose}></button>
<p className={'popup__title'}>Enter info about cat</p>
<TextField sx={{ mt: 1, mb: 1 }}
id="standard-required"
variant="standard"
label="Name"
required />
<TextField sx={{ mt: 1, mb: 1 }}
id="standard-required"
variant="standard"
label="Price"
required />
<FormControl sx={{ mt: 1, mb: 1 }}
variant="standard"
required>
<InputLabel id="breed-label">Breed</InputLabel>
<Select
labelId="filter-breed"
id="breed-select"
label="Breed"
value={breed}
onChange={handleChange}
>
{breedsName.map((item) => (
<MenuItem
key={item}
value={item}
id="breed-select"
>
{item}
</MenuItem>
))}
</Select>
</FormControl>
<FormControl sx={{ mt: 1, mb: 1 }}
variant="standard"
required>
<InputLabel id="color-label">Color</InputLabel>
<Select
labelId="filter-color"
id="color-select"
label="Color"
value={color}
onChange={handleChange}
>
{colorsArray.map((item) => (
<MenuItem
key={item}
value={item}
id="color-select"
>
{item}
</MenuItem>
))}
</Select>
</FormControl>
<TextField sx={{ mt: 1, mb: 1 }}
id="standard-required"
variant="standard"
label="Age"
required />
<ThemeProvider theme={theme}>
<Button sx={{ mt: 1, mb: 1 }}
variant="contained"
color={'secondary'}
onClick={handleSubmit}>
Add
</Button>
</ThemeProvider>
</div>
</section>
);
}
export default AddCatPopup;

The main problem was that you doesn't get id and value correctly. I understand why you wrote this code, but unfortunately the event which come into handleChange is MouseEvent | PointerEvent so you could not get the correct id and value. The reason why you could choose color in this part id === "breed-select" ? setBreed(value) : setColor(value); you always got id = undefined so the setColor is fired always. You should use second argument of handleChange function. You can copypaste below code to see how does it work now
import React from "react";
import "./AddCatPopup.css";
import {
Button,
FormControl,
InputLabel,
MenuItem,
Select,
TextField
} from "#mui/material";
import { theme } from "./theme";
import { ThemeProvider } from "#mui/material/styles";
function AddCatPopup({ breeds, isOpen, onClose, onAddCat }) {
const breedsName = breeds.map((item) => item.nameBreed);
const colorsArray = ["black", "white", "grey", "red", "multicolor"];
const [name, setName] = React.useState("");
const [price, setPrice] = React.useState(0);
const [age, setAge] = React.useState(0);
const [color, setColor] = React.useState("");
const [breed, setBreed] = React.useState("");
function handleChange(event, obj) {
const target = object.props;
const id = target.id;
const value = target.value;
/breed-option/.test(id) ? setBreed(value) : setColor(value);
}
function handleSubmit(e) {
e.preventDefault();
}
return (
<section className={`popup ${isOpen && "popup_opened"}`}>
<div className={"popup__container"}>
<button
type="button"
className={"popup__close-btn"}
onClick={onClose}
></button>
<p className={"popup__title"}>Enter info about cat</p>
<TextField
sx={{ mt: 1, mb: 1 }}
id="standard-required"
variant="standard"
label="Name"
required
/>
<TextField
sx={{ mt: 1, mb: 1 }}
id="standard-required"
variant="standard"
label="Price"
required
/>
<FormControl sx={{ mt: 1, mb: 1 }} variant="standard" required>
<InputLabel id="breed-label">Breed</InputLabel>
<Select
labelId="filter-breed"
id="breed-select"
label="Breed"
value={breed}
onChange={handleChange}
>
{breedsName.map((item, index) => (
<MenuItem key={item} value={item} id={'breed-option-' + index}>
{item}
</MenuItem>
))}
</Select>
</FormControl>
<FormControl sx={{ mt: 1, mb: 1 }} variant="standard" required>
<InputLabel id="color-label">Color</InputLabel>
<Select
labelId="filter-color"
id="color-select"
label="Color"
value={color}
onChange={handleChange}
>
{colorsArray.map((item, index) => (
<MenuItem key={item} value={item} id={"color-option-" + index}>
{item}
</MenuItem>
))}
</Select>
</FormControl>
<TextField
sx={{ mt: 1, mb: 1 }}
id="standard-required"
variant="standard"
label="Age"
required
/>
<ThemeProvider theme={theme}>
<Button
sx={{ mt: 1, mb: 1 }}
variant="contained"
color={"secondary"}
onClick={handleSubmit}
>
Add
</Button>
</ThemeProvider>
</div>
</section>
);
}
export default AddCatPopup;

Related

I want Link component from router dom to work only when validation is correct

I want if is possible the Link component from react-router-dom to not work until validations are made correct. If I remove the link, validation works as I want.
I saw something with ifValidate but I don't understand exactly how to apply it.
import { Link } from "react-router-dom";
const AgentProfile = () => {
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [phone, setPhone] = useState("");
const [proficiency, setProficiency] = useState("");
const [address, setAddress] = useState("");
const [city, setCity] = useState("");
const [firstNameError, setFirstNameError] = useState(false);
const [lastNameError, setLastNameError] = useState(false);
const [phoneError, setPhoneError] = useState(false);
const [proficiencyError, setProficiencyError] = useState(false);
const [addressError, setAddressError] = useState(false);
const [cityError, setCityError] = useState(false);
const handleSubmit = (e) => {
e.preventDefault();
setFirstNameError(false);
setLastNameError(false);
setPhoneError(false);
setProficiencyError(false);
setAddressError(false);
setCityError(false);
if (firstName === "") {
setFirstNameError(true);
}
if (lastName === "") {
setLastNameError(true);
}
if (phone === "") {
setPhoneError(true);
}
if (proficiency === "") {
setProficiencyError(true);
}
if (address === "") {
setAddressError(true);
}
if (city === "") {
setCityError(true);
}
if (firstName && lastName && phone && proficiency && address && city) {
console.log(firstName, lastName, phone, proficiency, address, city);
}
};
return (
<>
<Box sx={{ display: "flex", flexDirection: "column", width: "65%" }}>
<Box ml={10} pt={6}>
<Typography variant="h3" color="GrayText">
Hello! Please tell us a little bit about yourself.
</Typography>
</Box>
<form noValidate autoComplete="off" onSubmit={handleSubmit}>
<Box sx={{ display: "flex" }} ml={10} mt={2}>
<Box sx={{ width: "50%" }}>
{/* <Typography variant="body2">First Name</Typography> */}
<TextField
onChange={(e) => setFirstName(e.target.value)}
label="First Name"
type="text"
required
variant="outlined"
size="small"
error={firstNameError}
/>
</Box>
<Box>
{/* <Typography variant="body2">Last Name</Typography> */}
<TextField
onChange={(e) => setLastName(e.target.value)}
label="Last Name"
type="text"
required
variant="outlined"
size="small"
error={lastNameError}
/>
</Box>
</Box>
<Box sx={{ display: "flex" }} ml={10} mt={4}>
<Box sx={{ width: "50%" }}>
{/* <Typography variant="body2">Phone</Typography> */}
<TextField
onChange={(e) => setPhone(e.target.value)}
label="Phone"
type="text"
required
variant="outlined"
size="small"
error={phoneError}
/>
</Box>
<Box sx={{ width: "30%" }}>
{/* <Typography variant="body2">Work Proficiency</Typography> */}
<FormControl fullWidth size="small" required>
<InputLabel id="demo-simple-select-label">
Work Proficiency
</InputLabel>
<Select
onChange={(e) => setProficiency(e.target.value)}
labelId="demo-simple-select-label"
id="demo-simple-select"
value={proficiency}
label="Work Proficiency"
error={proficiencyError}
>
<MenuItem value={2}>Two years</MenuItem>
<MenuItem value={5}>Five years</MenuItem>
<MenuItem value={10}>Ten years</MenuItem>
</Select>
</FormControl>
</Box>
</Box>
<Box ml={10} mt={6}>
{/* <Typography variant="body2">Street Address</Typography> */}
<TextField
onChange={(e) => setAddress(e.target.value)}
label="Street Address"
type="text"
required
variant="outlined"
size="small"
sx={{ width: "80%" }}
error={addressError}
/>
</Box>
<Box ml={10} mt={6}>
{/* <Typography variant="body2">City</Typography> */}
<TextField
onChange={(e) => setCity(e.target.value)}
label="City"
type="text"
required
variant="outlined"
size="small"
sx={{ width: "40%" }}
error={cityError}
/>
</Box>
<Box mt={8} sx={{ display: "flex", justifyContent: "space-between" }}>
<Box ml={8}>
<Button variant="outlined" sx={{ borderRadius: "20px" }}>
Back
</Button>
</Box>
<Box mr={18}>
<Button
type="submit"
variant="contained"
sx={{ borderRadius: "20px" }}
>
<Link to="/experienceconfirm">Next</Link>
</Button>
</Box>
</Box>
</form>
</Box>
</>
);
};
export default AgentProfile;
Something like if validation is not correct link component to be disabled, and when user completes every field to become active.
You can prevent the default link action when the link is clicked and add an imperative navigation action in the form's submit handler when validation is passed. Additionally you can disable the button while any state is still falsey.
Example:
import { Link, useNavigate } from 'react-router-dom';
const AgentProfile = () => {
const navigate = useNavigate();
...
const handleSubmit = (e) => {
e.preventDefault();
setFirstNameError(false);
setLastNameError(false);
setPhoneError(false);
setProficiencyError(false);
setAddressError(false);
setCityError(false);
let isError = false;
if (!firstName) {
setFirstNameError(true);
isError = true;
}
if (!lastName) {
setLastNameError(true);
isError = true;
}
if (!phone) {
setPhoneError(true);
isError = true;
}
if (!proficiency) {
setProficiencyError(true);
isError = true;
}
if (!address) {
setAddressError(true);
isError = true;
}
if (!city) {
setCityError(true);
isError = true;
}
if (!isError) {
navigate("/experienceconfirm"); // <-- navigate on no error
}
};
return (
<>
<Box sx={{ display: "flex", flexDirection: "column", width: "65%" }}>
...
<form noValidate autoComplete="off" onSubmit={handleSubmit}>
...
<Box mt={8} sx={{ display: "flex", justifyContent: "space-between" }}>
<Box ml={8}>
<Button variant="outlined" sx={{ borderRadius: "20px" }}>
Back
</Button>
</Box>
<Box mr={18}>
<Button
type="submit"
variant="contained"
sx={{ borderRadius: "20px" }}
disabled={!(firstName && lastName && phone && proficiency && address && city)}
>
<Link
to="/experienceconfirm"
onClick={e => e.preventDefault()} // <-- prevent immediate navigation
>
Next
</Link>
</Button>
</Box>
</Box>
</form>
</Box>
</>
);
};
import { useEffect, useMemo } from "react";
import { Link } from "react-router-dom";
const AgentProfile = () => {
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [phone, setPhone] = useState("");
const [proficiency, setProficiency] = useState("");
const [address, setAddress] = useState("");
const [city, setCity] = useState("");
const [firstNameError, setFirstNameError] = useState(false);
const [lastNameError, setLastNameError] = useState(false);
const [phoneError, setPhoneError] = useState(false);
const [proficiencyError, setProficiencyError] = useState(false);
const [addressError, setAddressError] = useState(false);
const [cityError, setCityError] = useState(false);
useEffect(() => {
if (firstName === "") {
setFirstNameError(true);
}
if (lastName === "") {
setLastNameError(true);
}
if (phone === "") {
setPhoneError(true);
}
if (proficiency === "") {
setProficiencyError(true);
}
if (address === "") {
setAddressError(true);
}
if (city === "") {
setCityError(true);
}
}, [firstName, lastName, phone, proficiency, address, city])
const hasError = useMemo(
() => firstNameError || lastNameError || phoneError || proficiencyError || addressError || cityError
, [firstNameError, lastNameError, phoneError, proficiencyError, addressError, cityError]
)
return (
<>
<Box sx={{ display: "flex", flexDirection: "column", width: "65%" }}>
<Box ml={10} pt={6}>
<Typography variant="h3" color="GrayText">
Hello! Please tell us a little bit about yourself.
</Typography>
</Box>
<form noValidate autoComplete="off" onSubmit={handleSubmit}>
<Box sx={{ display: "flex" }} ml={10} mt={2}>
<Box sx={{ width: "50%" }}>
{/* <Typography variant="body2">First Name</Typography> */}
<TextField
onChange={(e) => setFirstName(e.target.value)}
label="First Name"
type="text"
required
variant="outlined"
size="small"
error={firstNameError}
/>
</Box>
<Box>
{/* <Typography variant="body2">Last Name</Typography> */}
<TextField
onChange={(e) => setLastName(e.target.value)}
label="Last Name"
type="text"
required
variant="outlined"
size="small"
error={lastNameError}
/>
</Box>
</Box>
<Box sx={{ display: "flex" }} ml={10} mt={4}>
<Box sx={{ width: "50%" }}>
{/* <Typography variant="body2">Phone</Typography> */}
<TextField
onChange={(e) => setPhone(e.target.value)}
label="Phone"
type="text"
required
variant="outlined"
size="small"
error={phoneError}
/>
</Box>
<Box sx={{ width: "30%" }}>
{/* <Typography variant="body2">Work Proficiency</Typography> */}
<FormControl fullWidth size="small" required>
<InputLabel id="demo-simple-select-label">
Work Proficiency
</InputLabel>
<Select
onChange={(e) => setProficiency(e.target.value)}
labelId="demo-simple-select-label"
id="demo-simple-select"
value={proficiency}
label="Work Proficiency"
error={proficiencyError}
>
<MenuItem value={2}>Two years</MenuItem>
<MenuItem value={5}>Five years</MenuItem>
<MenuItem value={10}>Ten years</MenuItem>
</Select>
</FormControl>
</Box>
</Box>
<Box ml={10} mt={6}>
{/* <Typography variant="body2">Street Address</Typography> */}
<TextField
onChange={(e) => setAddress(e.target.value)}
label="Street Address"
type="text"
required
variant="outlined"
size="small"
sx={{ width: "80%" }}
error={addressError}
/>
</Box>
<Box ml={10} mt={6}>
{/* <Typography variant="body2">City</Typography> */}
<TextField
onChange={(e) => setCity(e.target.value)}
label="City"
type="text"
required
variant="outlined"
size="small"
sx={{ width: "40%" }}
error={cityError}
/>
</Box>
<Box mt={8} sx={{ display: "flex", justifyContent: "space-between" }}>
<Box ml={8}>
<Button variant="outlined" sx={{ borderRadius: "20px" }}>
Back
</Button>
</Box>
<Box mr={18}>
<Button
type="submit"
variant="contained"
sx={{ borderRadius: "20px" }}
>
{hasError? "Next" : <Link to="/experienceconfirm">Next</Link>}
</Button>
</Box>
</Box>
</form>
</Box>
</>
);
};
export default AgentProfile;
I added useEffect to define whether the user inputted all fields or not.
If there is an error, the button only shows the string and has no action.

how to show data fetched from api in select mui

I'm trying to show the data, I fetched from Api in select menu. but there seems to be a issue. I'm getting the data, but it's not showing in the select menu. it just shows empty. but I can get the mapped data in console. it just not showing in the select component.
help me figure out. thanks in advance :)
here's my code
export function TransferRBTCard(props) {
const [TransferData, setTransferData] = useState([])
const [ContactValue, setContactValue] = useState('')
const handleChange = (event) => {
setContactValue(event.target.value);
};
const TokenData = () => {
axios.get('http://localhost:8006/api/v2/get/list').then(function (res) {
try {
var result = res.data.data;
console.log(result)
setTransferData(result)
}
catch (error) {
console.log(error)
}
})
}
useEffect(() => {
TokenData()
}, [])]
const handleSubmit = (evnt,) => {
evnt.preventDefault();
axios.post('http://localhost:8006/api/v2/add/transfer')
.then(response => {
if (response.data.success === true) {
alert(response.data.message)
}
})
.catch(error => {
console.log(error.message)
});
}
return (
<Card {...props}>
<CardContent>
<Stack direction="row" alignItems="center" gap={1}>
<ShareOutlinedIcon sx={{ color: "text.secondary" }} />
<Typography sx={{ fontSize: 16, fontWeight: 'bold' }} color="text.secondary" gutterBottom>
Transfer RBT
</Typography>
</Stack>
<Grid>
<FormControl size="small" fullWidth >
<Stack flexDirection='column' gap={1.5} mt={1}>
<InputLabel id="Contact Select" sx={{ mt: 1 }}>Select Contact</InputLabel>
<Select
labelId="Contact Select"
id="demo-simple-select"
value={ContactValue}
label='Select Contact'
onChange={handleChange}
>
{TransferData.map((data) => {
<MenuItem key={data.id} value={data.id}>{data.name}</MenuItem>
})}
</Select>
<TextField
id="filled-hidden-label-small"
label="Receiver" variant="outlined" size="small"
onChange={handleChange}
value={TransferData}
name="Receiver"
inputProps={
{ readOnly: true, }}
className="form-control"
/>
<TextField
id="filled-hidden-label-small" type='number'
label="Amount" variant="outlined" size="small"
onChange={handleChange}
name="Amount"
className="form-control"
/>
<TextField
id="filled-hidden-label-small"
label="Comments" variant="outlined"
multiline
rows={2}
onChange={handleChange}
name="Comments"
className="form-control"
/>
<Button
variant="contained"
type="submit"
onClick={handleSubmit}
sx={{ alignSelf: 'center', backgroundColor: '#000073' }} >Submit</Button>
</Stack>
</FormControl>
</Grid>
</CardContent>
</Card>
);
}
You are not returning from the map function (more correctly, you return undefined by not stating a return).
Change this:
{TransferData.map((data) => {
<MenuItem key={data.id} value={data.id}>{data.name}</MenuItem>
})}
to this:
{TransferData.map((data) => (
<MenuItem key={data.id} value={data.id}>{data.name}</MenuItem>
))}
Note that it is the same as writing:
{TransferData.map((data) => {
return <MenuItem key={data.id} value={data.id}>{data.name}</MenuItem>
})}

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()

When i upload an image the dropdown menu become in a single and button also lost it's css (I am using material UI React.js)

As you can see in the below picture when i came to this page it look like this and it's perfectly fine as i want
but when i upload in image (using dropzoneArea) material UI it become look like this and all the drop down menu will be in single line and also you will see submit button also changed
uploadProduct.js
import React, { useState,useEffect } from "react";
import { useHistory, useLocation } from "react-router-dom";
import {
Typography,
Grid,
Button,
FormGroup,
TextField,
Select,
MenuItem,
InputLabel,
FormControl,
InputAdornment,
Input,
} from "#mui/material";
import "./styles.css";
import FileUpload from "../../utils/FileUpload";
import Axios from "axios";
import MuiPhoneNumber from "material-ui-phone-number";
import decode from "jwt-decode";
export const UploadProduct = (props) => {
const location = useLocation();
const history = useHistory();
const [Token_Id, setToken_Id] = useState(localStorage.getItem("token"))
const [Title, setTitle] = useState("");
const [userId, setuserId] = useState(0);
const [Description, setDescription] = useState("");
const [Price, setPrice] = useState();
const [Category, setCategory] = useState("");
const [perGiven, setperGiven] = useState("");
const [Phone, setPhone] = useState("");
const [Address, setAddress] = useState("");
const [Name, setName] = useState("")
const [Images, setImages] = useState([]);
const handleLogout = () => {
localStorage.removeItem("token");
history.push("/");
setName("");
props.showAlert("Logout Successfully", "success");
};
useEffect(() => {
const token = Token_Id;
if (token) {
const { exp, name, id } = decode(token);
setuserId(id)
setName(name);
if (Date.now() >= exp * 1000) {
handleLogout();
}
}
setToken_Id(localStorage.getItem("token"));
}, [location]);
const updateImages = (newImages) => {
setImages(newImages);
};
const onSubmit = (event) => {
event.preventDefault();
if (
!userId ||
!Name ||
!Title ||
!Description ||
!Price ||
!Category ||
!perGiven ||
!Phone ||
!Address ||
!Images
) {
return alert("fill all the fields first!");
}
const variables = {
userId: userId,
userName: Name,
title: Title,
description: Description,
category: Category,
price: Price,
rentType: perGiven,
images: Images,
phoneNumber: Phone,
address: Address,
};
Axios.post("/product/uploadProduct", variables).then((response) => {
if (response.data.success) {
alert("Product Successfully Uploaded");
history.push("/");
} else {
alert("Failed to upload Product");
}
});
};
return (
<div
className="parentDiv"
style={{marginTop: "70px", paddingBottom: "10px" }}
>
<div style={{ maxWidth: "700px", margin: "2rem auto" }}>
<div style={{ textAlign: "center", marginBottom: "2rem" }}>
<Typography variant="h4">Anything for rent?</Typography>
</div>
<FormGroup>
{/* DropZone */}
<FileUpload refreshFunction={updateImages} />
<br />
<TextField
variant="standard"
required
fullWidth
id="title"
label="AD TITLE"
name="title"
value={Title}
autoFocus
onChange={(e) => setTitle(e.target.value)}
/>
<br />
<TextField
variant="standard"
required
fullWidth
id="description"
label="DESCRIPTION"
name="description"
value={Description}
onChange={(e) => setDescription(e.target.value)}
/>
<br />
<FormControl variant="standard" sx={{ m: 0, minWidth: 120 }}>
<InputLabel id="demo-simple-select-label">
CHOOSE CATEGORY
</InputLabel>
<Select
labelId="demo-simple-select-label"
label="CHOOSE CATEGORY"
name="category"
onChange={(e) => {
setCategory(e.target.value);
}}
className="input"
style={{display: "flex", alignItems: "center"}}
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value="Tools">Tools</MenuItem>
<MenuItem value="Apparels">Apparels</MenuItem>
<MenuItem value="Vehicles">Vehicles</MenuItem>
<MenuItem value="Equipments">Equipments</MenuItem>
<MenuItem value="Footwear">Footwear</MenuItem>
</Select>
</FormControl>
<br />
<MuiPhoneNumber
className="my-2"
label="PHONE NUMBER"
variant="standard"
value={Phone}
defaultCountry={"pk"}
onChange={setPhone}
/>
<br />
<Grid container className="my-1">
<Grid item>
<InputLabel htmlFor="standard-adornment-amount">
SET A PRICE
</InputLabel>
<Input
id="standard-adornment-amount"
required={true}
value={Price}
onChange={(e) => {
setPrice(e.target.value);
}}
startAdornment={
<InputAdornment position="start">Rs</InputAdornment>
}
/>
{/* <TextField required fullWidth id="price" label="Price" name="price" value={Price} onChange={(e) => {setPrice(e.target.value)}} variant="standard" /> */}
</Grid>
<Grid
item
className="mx-2"
alignItems="stretch"
style={{ display: "flex" }}
>
<FormControl
className="my-1"
variant="standard"
sx={{ m: 2, minWidth: 150 }}
>
<InputLabel id="demo-simple-select-standard-label">
Rent type
</InputLabel>
<Select
labelId="demo-simple-select-standard-label"
id="demo-simple-select-standard"
value={perGiven}
onChange={(e) => {
setperGiven(e.target.value);
}}
label="rent type"
>
<MenuItem value="">
<em>None</em>
</MenuItem>
<MenuItem value="Day">Day</MenuItem>
<MenuItem value="Week">Week</MenuItem>
<MenuItem value="Month">Month</MenuItem>
</Select>
</FormControl>
</Grid>
</Grid>
<TextField
className="my-2"
variant="standard"
required
fullWidth
id="address"
label="ADDRESS"
name="address"
value={Address}
onChange={(e) => setAddress(e.target.value)}
/>
<Button className="my-3" variant="contained" onClick={onSubmit}>
Submit
</Button>
</FormGroup>
</div>
</div>
);
};
FileUpload.js
import React, { useState } from "react";
import { DropzoneArea } from "material-ui-dropzone";
import Axios from "axios";
function FileUpload(props) {
const [Images, setImages] = useState([]);
const onDrop = (files) => {
let formData = new FormData();
const config = {
header: { "content-type": "multipart/form-data" },
};
formData.append("file", files[0]);
//save the Image we chose inside the Node Server
Axios.post("/product/uploadImage", formData, config).then((response) => {
if (response.data.success) {
setImages([...Images, response.data.image]);
props.refreshFunction([...Images, response.data.image]);
} else {
alert("Failed to save the Image in Server");
}
});
};
const onDelete = (image) => {
const currentIndex = Images.indexOf(image);
let newImages = [...Images];
newImages.splice(currentIndex, 1);
setImages(newImages);
props.refreshFunction(newImages);
};
return (
<div style={{ display: "flex", justifyContent: "space-between" }}>
<DropzoneArea
onDrop={onDrop}
multiple={false}
maxSize={5000000}
showPreviewsInDropzone={false}
>
{({ getRootProps, getInputProps }) => (
<div
style={{
width: "300px",
height: "240px",
border: "1px solid lightgray",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
{...getRootProps()}
>
<input {...getInputProps()} />
</div>
)}
</DropzoneArea>
<div
style={{
display: "flex",
marginLeft: "10px",
width: "350px",
height: "250px",
overflowX: "scroll",
}}
>
{Images.map((image, index) => (
<div onClick={() => onDelete(image)}>
<img
style={{ minWidth: "200px", width: "220px", height: "230px" }}
src={`http://localhost:5000/${image}`}
alt={`productImg-${index}`}
/>
</div>
))}
</div>
</div>
);
}
export default FileUpload;
As you can see in the UploadProduct.js i called the FileUpload component for uploading the files.
If you find any error or bug please let me know and any suggestion will be helpfull
TIA

React + Formik + redux: An unhandled error was caught from submitForm() TypeError: Object(...) is not a function

I'am struggling with this error, I'm using Formik + redux to handle React Form, so I had this following warning when I submit button:
react_devtools_backend.js:2560 Warning: An unhandled error was caught from submitForm() TypeError: Object(...) is not a function
at onSubmit (LoginContainer.js:72)
at Formik.tsx:849
at Formik.tsx:1200
at Formik.tsx:756
According to the warning, the error is on line 72 : where is wrote :
dispatch(login(payload.email, payload.password));
Even if I deleted keyword dispatch , I still get error.
Here is my LoginContainer funtional component:
import React from "react";
import { Link as RouterLink } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import {
Grid,
Typography,
TextField,
Container,
Link,
Box,
Button,
Checkbox,
InputLabel,
FormGroup,
FormControlLabel,
IconButton,
OutlinedInput,
FormControl,
FormHelperText,
InputAdornment,
} from "#material-ui/core";
import Visibility from "#material-ui/icons/Visibility";
import VisibilityOff from "#material-ui/icons/VisibilityOff";
import * as Yup from "yup";
import { Formik } from "formik";
import AuthLayout from "../../../components/AuthLayout";
import { FORGOTPASSWORD } from "../../../navigation/CONSTANT";
import login from "../../../services/AuthService";
//styles
//Login component
export function LoginContainer() {
const [rootValues, setRootValues] = React.useState({
showPassword: true,
});
// ======= Password function ===========/
const handleClickShowPassword = () => {
setRootValues({
showPassword: !rootValues.showPassword,
});
};
const handleMouseDownPassword = (event) => {
event.preventDefault();
};
//=================== end ===============/
const dispatch = useDispatch();
const initialValues = {
email: "example#rilc.com",
password: "motdepasse",
};
const validationSchema = Yup.object().shape({
email: Yup.string()
.email("L'adresse mail doit être valide")
.max(50)
.required("L'adresse mail est obligatoire"),
password: Yup.string().max(50).required("Le mot de passe est obligatoire"),
});
function onSubmit(values, { setSubmitting }) {
/*alert(JSON.stringify(values, null, 2));*/
const payload = {
email: values.email,
password: values.password,
};
dispatch(login(payload.email, payload.password));
}
return (
<AuthLayout>
<Box
sx={{
backgroundColor: "background.default",
display: "flex",
flexDirection: "column",
height: "100%",
justifyContent: "center",
}}
>
<Container maxWidth="sm">
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={onSubmit}
>
{({
errors,
handleBlur,
handleChange,
handleSubmit,
isSubmitting,
touched,
values,
}) => (
<form onSubmit={handleSubmit}>
<Box sx={{ mb: 3, ml: 10 }}>
<Typography color="textPrimary" variant="h3" textAlign="left">
Connexion
</Typography>
</Box>
<Grid container spacing={3}></Grid>
<Box
sx={{
pb: 1,
pt: 4,
}}
></Box>
<Box
sx={{
ml: 10,
}}
>
<TextField
error={Boolean(touched.email && errors.email)}
fullWidth
helperText={touched.email && errors.email}
label="Email"
margin="normal"
name="email"
onBlur={handleBlur}
onChange={handleChange}
type="email"
value={values.email}
variant="outlined"
/>
<FormControl
sx={{ mt: 3 }}
variant="outlined"
fullWidth
onChange={handleChange}
onBlur={handleBlur}
error={Boolean(touched.password && errors.password)}
>
<InputLabel htmlFor="outlined-adornment-password">
Password
</InputLabel>
<OutlinedInput
id="outlined-adornment-password"
type={rootValues.showPassword ? "text" : "password"}
value={values.password}
name="password"
endAdornment={
<InputAdornment position="end">
<IconButton
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{rootValues.showPassword ? (
<Visibility />
) : (
<VisibilityOff />
)}
</IconButton>
</InputAdornment>
}
label="Password"
/>
<FormHelperText id="component-error-text">
{touched.password && errors.password}
</FormHelperText>
</FormControl>
<Box
sx={{
display: "grid",
columnGap: 2,
rowGap: 1,
mt: 3,
gridTemplateColumns: "repeat(2, 0.5fr)",
}}
>
<Box>
<FormGroup>
<FormControlLabel
control={<Checkbox defaultChecked />}
label="Se souvenir de moi"
/>
</FormGroup>
</Box>
<Box sx={{ mt: 1, textAlign: "right" }}>
<Link component={RouterLink} to={FORGOTPASSWORD}>
Mot de passe oublié?
</Link>
</Box>
</Box>
<Box sx={{ py: 2 }}>
<Button
color="primary"
disabled={isSubmitting}
fullWidth
size="large"
type="submit"
variant="contained"
>
Se connecter
</Button>
</Box>
</Box>
</form>
)}
</Formik>
</Container>
</Box>
</AuthLayout>
);
}
Thanks for you help.

Categories

Resources