Hey guys I am learning react and have a form to edit book details. I am using django in the backend. I am not able to update the e-book which is a switch to turn on and off according to whether e-book is available or not. The switch works fine, but no data is being changed in the database. I am confused on how to work with the switch and saw lots of resources saying different things which is quite difficult to understand. Rest of the fields are getting updated correctly. Can someone tell me what changes I have to make in this switch to make it work??
code
import React, {useEffect, useState} from 'react'
import axiosInstance from '../../axios';
import { useForm, Controller } from 'react-hook-form';
//MaterialUI
import Button from '@material-ui/core/Button';
import CssBaseline from '@material-ui/core/CssBaseline';
import TextField from '@material-ui/core/TextField';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import Container from '@material-ui/core/Container';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Switch from '@material-ui/core/Switch';
import Select from '@material-ui/core/Select';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import FormControl from '@material-ui/core/FormControl';
const useStyles = makeStyles((theme) => ({
paper: {
marginTop: theme.spacing(8),
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
},
bookformbody: {
display: "flex",
backgroundColor: "#ffff",
height: "100vh",
},
form: {
width: '100%', // Fix IE 11 issue.
marginTop: theme.spacing(3),
},
submit: {
margin: theme.spacing(3, 0, 2),
},
}));
function BookEdit() {
const initialFormData = Object.freeze({
id: '',
summary: '',
published_date: '',
e_book: false,
});
const [formData, updateFormData] = useState(initialFormData);
useEffect(() => {
axiosInstance.get('api/books/details/view/').then((res) => {
updateFormData({
...formData,
['summary']: res.data.summary,
['published_date']: res.data.published_date,
['e_book']: res.data.e_book,
});
console.log(res.data);
});
}, [updateFormData]);
const handleChange = (e) => {
if(e.target.name === "e_book"){
return(
updateFormData({
...formData,
[e.target.name]: e.target.checked
})
)
}
updateFormData({
...formData,
// Trimming any whitespace
[e.target.name]: e.target.value
});
};
const onSubmit = (data) =>{
let formData = new FormData();
formData.append('summary', data.summary);
formData.append('published_date', data.published_date);
formData.append('e_book', data.e_book);
axiosInstance.put('api/books/details/edit/', formData);
} ;
const classes = useStyles();
const { register, handleSubmit, control, errors } = useForm();
return (
<>
<Header />
<div className={classes.bookformbody}>
<SideBar />
<Container component="main" maxWidth="sm">
<CssBaseline />
<div className={classes.paper}>
<Typography component="h1" variant="h5">
Edit Book Details
</Typography>
<form className={classes.form} noValidate onSubmit={handleSubmit(onSubmit)}>
<Grid container spacing={2}>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
id="summary"
label="Book Summary"
name="summary"
autoComplete="summary"
value={formData.summary}
onChange={handleChange}
inputRef={register({maxLength: 1000})}
multiline
rows={4}
/>
</Grid>
<Grid item xs={12}>
<TextField
variant="outlined"
required
fullWidth
type="date"
label="Published Date"
name="published_date"
autoComplete="published_date"
value={formData.published_date}
onChange={handleChange}
inputRef={register({required: true})}
InputLabelProps={{
shrink: true,
}}
/>
</Grid>
<Grid item xs={12}>
<InputLabel id="e-book-switch">E-Book</InputLabel>
<Controller
name="e_book"
control={control}
as={
<Switch size="small"
id="e-book-switch"
type="checkbox"
name="e_book"
onChange={handleChange}
// inputRef={register}
value={formData.e_book}
checked={formData.e_book}
/>
}
/>
</Grid>
</Grid>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Update
</Button>
</form>
</div>
</Container>
</div>
</>
)
}
export default BookEdit;
You are passing props to Switch directly, but what you should do is to use Controller props, and Controller will then pass it down to Switch:
<Controller as={Switch} value={formData.e_book} ... />
Otherwise you need to use render, not as This is actually described pretty good here: https://react-hook-form.com/api/#Controller
UPDATE
Here is the sandbox where it is working fine with above changes - https://codesandbox.io/s/kind-nash-s94v0
What i did there is simply this:
<Controller
name="e_book"
control={control}
render={(props) => {
return (
<Switch
size="small"
id="e-book-switch"
type="checkbox"
name="e_book"
onChange={handleChange}
// inputRef={register}
value={formData.e_book}
checked={formData.e_book}
/>
);
}}
/>
You are initializing the value as a string at the beginning of BookEdit(). Try to set initialFormData like this:
const initialFormData = Object.freeze({
id: '',
summary: '',
published_date: '',
e_book: false,
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With