get selected file object with react-hook-form - reactjs

I have a component which uploads a file. When an image is selected it previews it in another component.
So, when an image is selected, I need to access it. I tried using getValues() and watch() from react-hook-form but it is returning me path of the file in string form not the file object.
<div className="photo">
<Avatar
src={
// it gives path of the file as string
getValues('photo')
? URL.createObjectURL(getValues('photo')[0])
: "https://icon-library.com/images/no-image-icon/no-image-icon-0.jpg"
}
alt="photo preview"
sx={{ width: "200px", height: "200px" }}
/>
<label htmlFor="contained-button-file">
<Controller
name="photo"
control={control}
render={({ field }) => (
<Input
{...field}
accept="image/*"
id="contained-button-file"
type="file"
error={Boolean(errors["photo"])}
helperText={errors["photo"]?.message}
/>
)}
/>
<Button variant="contained" component="span">
Upload
</Button>
</label>
</div>
Somehow, watch() and getValues() reading value of input field here. While they should be returning e.target.files instead.
It can be checked here and here, It works the same way. It returns the files.
Why it does not return files but returning value here?

Using work around for now. Using setValue() and calling it on change of the input file.
<div className="photo">
<Avatar
src={
watch('photo')
? URL.createObjectURL(watch('photo')[0])
: "https://icon-library.com/images/no-image-icon/no-image-icon-0.jpg"
}
alt="photo preview"
sx={{ width: "200px", height: "200px" }}
/>
<label htmlFor="contained-button-file">
<Input
accept="image/*"
id="contained-button-file"
type="file"
error={Boolean(errors["photo"])}
onChange={(e) => setValue("photo", e.target.files)}
multiple
helperText={errors["photo"]?.message}
/>
<Button variant="contained" component="span">
Upload
</Button>
</label>
</div>

Related

Formik unable to submit data showing response TypeError: Cannot read properties of undefined (reading 'name')

i am unable to submit data from formik to django server side, tried sending same data with post man and it worked.
but keep showing
Warning: An unhandled error was caught from submitForm() TypeError: Cannot read properties of undefined (reading 'name') error. from react using formik and material ui
do know if it the version causing it. how can i resolve this issue.. checked online yet to see similar issue. also on my server side(drf) the audio data failed to store to the assigned folder for storing audio's
<form action=""
className="create_form"
// onSubmit={(e)=>{
// e.preventDefault();
// formik.handleSubmit();
// }}
onSubmit={formik.handleSubmit}
>
<Box component="form" sx={{ width: '100%', display:'flex',flexDirection:'column',gap:'20px' }}
>
<TextField
id="outlined-basic"
label="Artist Name"
variant="outlined"
name="artist_name"
value={formik.values.artist_name}
onChange={formik.handleChange}
/>
<TextField id="outlined-basic" label="Title" variant="outlined" name='title' onChange={formik.handleChange} value={formik.values.title} />
<IconButton aria-label="upload picture" component="label" sx={{ background:'grey',width:'20%',borderRadius:'5%' }}>
<input hidden accept="audio" type="file" name='audio' onChange={(e)=>formik.setFieldValue("audio",e.currentTarget.files[0])} />
<AudioFile />
</IconButton>
<IconButton aria-label="upload picture" component="label" sx={{ background:'grey',width:'20%',borderRadius:'5%' }}>
<input hidden accept="image" type="file" name='image' onChange={(e)=>formik.setFieldValue("image",e.currentTarget.files[0])} />
<PhotoCamera />
</IconButton>
{/* <input type="file" value={audio} onChange={handleAudioUpload} name='audio' /> */}
<FormControl sx={{width:'50%' , color:'black',}}>
<InputLabel id="demo-simple-select-label">Genre</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={formik.values.genre}
name='genre'
label="Genre"
onChange={formik.handleChange('genre')}
>
{song_genre.map(genre=>(
<MenuItem key={genre.id} value={genre.id} sx={{color:'black'}}>{genre.name}</MenuItem>
))}
</Select>
</FormControl>
<TextField id="outlined-basic" className="description" label="Desciption" variant="outlined" rows={6} multiline />
</Box>
<br />
<Button variant="contained" sx={{width:'30%'}} type='submit' >Submit</Button>
</form>
const formik=useFormik({
initialValues:{
artist_name:"",
title:"",
// audio:"",
// image:"",
description:"",
genre:"",
},
validationSchema:Yup.object({
artist_name:Yup.string().required(),
title:Yup.string().required(),
// audio:Yup.string().required(),
}),
onSubmit:((values)=>{
const data={
artist_name:values.artist_name,
title:values.title,
audio: values.audio.name,
image:values.image.name,
description:values.description,
genre:values.genre,
}
console.log(data)
fetch('http://127.0.0.1:8000/create',{
method:"POST",
body:JSON.stringify(data),
headers:{
"Content-Type": "application/json",
"Accept":"application/json"
},
}).then(res=>res.json())
.then(data=>{
try{
console.log(data)
}catch(error){
console.error(error)
}
})
}),
// audioUpload: ((event)=>{
// formik.setFieldValue('audio',event.target.files[0])
// })
})

React Application form data with image uploading field cannot POST to my backend api

First I am trying to post my form data without an image then that data is passed to the backend successfully. then I try to send an image to the backend with form data and then I got an error. image uploading field is a not required field. how I pass the image to the backend with form data.
This is my basic info tab image uploading field
<Grid item xs={6} md={3} sm={4}>
<Controller
name="avatar"
id="avatar"
control={control}
render={({ field }) => (
<TextField
{...field}
className="mt-4 mb-8"
type="file"
onChange={(event) => {
// console.log(event.target.files[0]);
setSelectedImage(event.target.files[0]);
}}
autoFocus
value={selectedImage}
variant="outlined"
size="small"
fullWidth
/>
)}
/>
</Grid>
this is my user.js file return
return (
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(onSubmit)}>
<Root
header={<UserHeader />}
contentToolbar={
<Tabs
value={tabValue}
onChange={handleTabChange}
indicatorColor="primary"
textColor="primary"
variant="scrollable"
scrollButtons="auto"
classes={{ root: 'w-full h-64' }}
>
<Tab className="h-64" label="Basic Info" />
// <Tab className="h-64" label="User Images" />
</Tabs>
}
content={
<div className="p-16 sm:p-16 max-w-2xl">
<div className={tabValue !== 0 ? 'hidden' : ''}>
<BasicInfoTab />
</div>
<div className={tabValue !== 1 ? 'hidden' : ''}>
<ImagesTab />
</div>
{/* <div>
<input type="file" name="file_upload" onChange={onFileChage}/>
</div>
<div>
<button>Submit Data</button>
</div>*/}
</div>
}
innerScroll
/>
</form>
</FormProvider>
);
}
This is my error

react-hook-form radio with custom style

I have a form (react-hook-form) for update data with two options radio.
In this form I can read datas and display it.
But when I want to change the value, my interface doesn't update the display.
Where am I wrong?
Here is my code snippet :
<Controller
name={`evaluations.${index}.check`}
control={control}
render={({ field }) => {
return (
<>
<div className={'radioCheck'}>
<input
{...field}
style={{ display: "none" }}
type='radio'
name={auditEval.checkpoint?.id.toString()}
id={`ok${auditEval.checkpoint?.id}`}
value={'true'}
defaultChecked={auditEval.check == true}
/>
<label htmlFor={`ok${auditEval.checkpoint?.id}`}>
<FontAwesomeIcon icon={faCheck} />
</label>
</div>
<div className={'radioCross'}>
<input
{...field}
style={{ display: "none" }}
type='radio'
name={auditEval.checkpoint?.id.toString()}
id={`nok${auditEval.checkpoint?.id}`}
value={'false'}
defaultChecked={auditEval.check == false}
/>
<label htmlFor={`nok${auditEval.checkpoint?.id}`}>
<FontAwesomeIcon icon={faX} />
</label>
</div>
</>
)
}}
/>

Why can't I get values of Date and Text Area in Formik?

I am using Formik and Yup for a form control in React application. I use also Semantic UI. In the application, when I click the submit button, whereas I can read the values from FormField elements and see them on Console, I can not get the value of Date and Text Area elements and they appear blank on Console. How can I solve this out?
Here I define the intial values.
const initialValues = {
jobTitle: { id: "" },
deadline: "",
description: "",
};
Then here I try to get the values from form element
return (
<div>
<Card fluid>
<Card.Content>
<Card.Header>Create A New Job Ad</Card.Header>
<Divider inverted />
<Formik
initialValues={initialValues}
validationSchema={jobAdCreateSchema}
onSubmit={(values) => {
handleSubmit(values);
}}
>
{({ values, setFieldValue }) => (
<div>
<pre>{JSON.stringify(values, undefined, 2)}</pre>
<Form className="ui form">
<FormField>
<label>Job Title</label>
<Dropdown
selection
placeholder="Select a Job Title"
name="jobTitle"
fluid
options={jobTitleOption}
value={values.jobTitle.id}
onChange={(_, { value }) =>
setFieldValue("jobTitle.id", value)
}
/>
</FormField>
<FormField>
<label>Application Deadline</label>
<input
name="deadline"
style={{ width: "100%" }}
type="date"
placeholder="Application Deadline"
value={values.deadline}
onChange={formik.handleChange}
/>
</FormField>
<FormField>
<label>Job Description</label>
<TextArea
name="description"
placeholder="Job Description"
style={{ minHeight: 100 }}
value={values.description}
onChange={formik.handleChange}
/>
</FormField>
<FormField>
<Button color="green" type="submit">
Submit
</Button>
</FormField>
</Form>
</div>
)}
</Formik>
</Card.Content>
</Card>
</div>
);
formik isn't defined, so your assigning an onChange function that doesn't exist.
Destructure handleChange from the argument, then assign it to the inputs like so:
{({ values, setFieldValue, handleChange }) => (
//...
<input
name="deadline"
style={{ width: "100%" }}
type="date"
placeholder="Application Deadline"
value={values.deadline}
onChange={handleChange}
/>
)}
Live demo

Material UI: File Upload using ButtonBase

In Material UI Documentation, they showed how to create an "Upload" button by hiding the input file and then adding the Button component inside the label. (see: https://material-ui.com/demos/buttons/)
Now, I want a different button, so I'm working with ButtonBase but it's not working - file select pop-up doesn't show. I'm not sure if I'm missing anything, maybe I'm missing some parameter to pass it?
<input
accept="image/*"
className="d-none"
id="image-upload"
type="file"
/>
<label htmlFor="image-upload"
className="d-block" >
<Button component="span">
Upload
</Button> {/* working */}
<ButtonBase>
test
</ButtonBase> {/* not working*/}
</label>
ButtonBase API: https://material-ui.com/api/button-base/
First, what version are you running? Material-UI is a very fast project so you need to make sure you're checking the documentation for whatever version you are at.
I favor using explicit events (ref in this case) and this works for me under 3.1.0
<input
ref={'file-upload'}
type='file'
/>
<ButtonBase
onClick={e => {
this.refs['file-upload'].click()
}}
>
<div style={{
color: 'red',
backgroundColor: 'yellow',
border: '1px solid green',
}}
>
Upload!
</div>
</ButtonBase>
<hr />
<Button
type='file'
onClick={e => {
this.refs['file-upload'].click()
}}
>
File Upload Material
</Button>
I use something similar to this in one of my projects and I just hide the <input type='file' /> element.
the same can be implement with hooks
export default function myForm(props) {
const inputEl = React.useRef(null);
const onButtonClick = () => {
console.log("inside")
// `current` points to the mounted file input element
inputEl.current.click();
};
return (
<React.Fragment>
Upload Photos
<br/>
<input
accept="image/*"
className={classes.input}
id="outlined-button-file"
multiple
type="file"
ref={inputEl}
/>
<label htmlFor="outlined-button-file">
<ButtonBases
onClick={()=>onButtonClick()}
/>
</label>
</React.Fragment>
)}
Don't forget to call onClick inside ButtonBasses component.
export default function ButtonBases(props) {
const classes = useStyles();
return (
<div className={classes.root}>
<ButtonBase
...
onClick={props.onClick}
>
....
</ButtonBase>
))}
</div>
);
}

Resources