react-hook-form radio with custom style - reactjs

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>
</>
)
}}
/>

Related

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

get selected file object with react-hook-form

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>

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

React Hook using Controller for a custom Input

I'm using react-hook-form to valid fields before submitting my form. However, I'm trying to change one input to be react-number-format, but it is not using the same input style and it's not working for the register error validation.
import React, { useState } from 'react';
import { Controller, useForm } from "react-hook-form";
import {
Form,
Label,
Input,
Button
} from 'reactstrap';
import { FormGroup } from '#material-ui/core';
import moment from 'moment';
import DatePicker from "reactstrap-date-picker";
import NumberFormat from 'react-number-format';
const setErrorStyle = (name) => {
return {
borderColor: name ? 'red' : '',
boxShadow: name ? '0 0 1.5px 1px red' : ''
}
}
const Test = () => {
const [ addBill, setAddBill ] = useState({
debitAmt: '',
invoiceNumber: '',
memo: '',
invoiceDate: moment().format('YYYY-MM-DD'),
});
const { register, handleSubmit, errors, control } = useForm();
const submitAddBill = (data) => {
console.log(data);
}
return (
<>
<Form onSubmit={handleSubmit(submitAddBill)}>
<div className="row">
<div className="col-sm-2">
<FormGroup className="mr-10 mb-10">
<Label for="debitAmt" className="mr-sm-10">Debit Amt</Label>
<Controller
as={
<NumberFormat
thousandSeparator={true}
prefix={"$"}
onValueChange={(v) => {
setAddBill({...addBill, debitAmt: v.floatValue === undefined ? '' : v.floatValue})
}}
/>
}
name="debitAmt"
id="debitAmt"
variant="outlined"
defaultValue={addBill.debitAmt}
innerRef={register({ required: true })} aria-invalid={errors.debitAmt ? "true" : "false"}
control={control}
style={setErrorStyle(errors.debitAmt)}
/>
{errors.debitAmt && (
<span style={{ color: "red" }} role="alert">required</span>
)}
</FormGroup>
</div>
<div className="col-sm-2">
<FormGroup className="mr-10 mb-10">
<Label for="invoiceDate" className="mr-sm-10">Invoice Date</Label>
<DatePicker name="invoiceDate" id="invoiceDate"
value={addBill.invoiceDate} onChange={(e) => setAddBill({...addBill, invoiceDate: e ? moment(e).format('YYYY-MM-DD') : ''})}
innerRef={register({ required: true })} aria-invalid={errors.invoiceDate ? "true" : "false"}
style={setErrorStyle(errors.invoiceDate)}
/>
{errors.invoiceDate && (
<span style={{ color: "red" }} role="alert">required</span>
)}
</FormGroup>
</div>
<div className="col-sm-3">
<FormGroup className="mr-10 mb-10">
<Label for="invoiceNumber" className="mr-sm-10">Invoice Number</Label>
<Input type="text" name="invoiceNumber" id="invoiceNumber" placeholder="1234567"
innerRef={register({ required: true })} aria-invalid={errors.invoiceNumber ? "true" : "false"}
value={addBill.invoiceNumber} onChange={(e) => setAddBill({...addBill, invoiceNumber: e.target.value})}
style={setErrorStyle(errors.invoiceNumber)}
/>
{errors.invoiceNumber && (
<span style={{ color: "red" }} role="alert">required</span>
)}
</FormGroup>
</div>
<div className="col-sm-3">
<FormGroup className="mr-10 mb-10">
<Label for="memo" className="mr-sm-10">Memo</Label>
<Input type="text" name="memo" id="memo" placeholder="Memo"
innerRef={register()} aria-invalid={errors.memo ? "true" : "false"}
value={addBill.memo} onChange={(e) => setAddBill({...addBill, memo: e.target.value})}
style={setErrorStyle(errors.memo)}
/>
</FormGroup>
</div>
</div>
<Button type="submit" color="primary" size="sm" className="w-auto">Add Bill</Button>
</Form>
</>
)
}
export default Test;
Also, when I submit the form and check the log, the debitAmt data is not there.
Thanks
The prop innerRef doesn't exist on NumberFormat component instead use getInputRef prop on NumberFormat
Example Implementation
<FormGroup className="mr-10 mb-10">
<Label for="debitAmt" className="mr-sm-10">
Debit Amt
</Label>
<Controller
as={
<NumberFormat
thousandSeparator={true}
prefix={"$"}
onValueChange={(v) => {
setAddBill({
...addBill,
debitAmt: v.floatValue === undefined ? "" : v.floatValue
});
}}
/>
}
name="debitAmt"
id="debitAmt"
variant="outlined"
defaultValue={addBill.debitAmt}
getInputRef={register({ required: true })}
aria-invalid={errors.debitAmt ? "true" : "false"}
control={control}
style={setErrorStyle(errors.debitAmt)}
/>
{errors.debitAmt && (
<span style={{ color: "red" }} role="alert">
required
</span>
)}
</FormGroup>
Example Sandbox here

Netlify form submission blank with react-final-form plugin

I am using react-final-form to develop a multi-page wizard form but am now stuck on sending my submissions to Netlify.
Netlify has detected my form but on submit doesn't receive my forms data
This is my first time using Netlify to handle form submissions so I'm not sure if I'm doing something
wrong on Netlifys side or react-final-forms side.
important
im using GATSBY
index.js
<Wizard onSubmit={onSubmit}>
<Wizard.Page>
<div>
<div>
<label css={label}>> Name</label>
</div>
<Field
autocomplete="off"
css={input}
name="Name"
component="input"
type="text"
placeholder="$"
validate={required}
/>
<Error name="Name" />
</div>
<div>
<div>
<label css={label}>> Email</label>
</div>
<Field
autocomplete="off"
css={input}
name="Email"
component="input"
type="email"
placeholder="$"
validate={required}
/>
<Error name="Email" />
</div>
<div>
<div>
<label css={label}>> Social handle</label>
</div>
<Field
autocomplete="off"
css={input}
name="Social"
component="input"
type="text"
placeholder="$"
/>
<Error name="Social" />
</div>
</Wizard.Page>
<Wizard.Page>
<div>
<div>
<label css={label}>> What can we do for you?</label>
</div>
<div>
<label
style={{
display: 'flex',
alignItems: 'center',
paddingTop: '0.5em',
}}
>
<Field
css={checkbox}
onClick={play}
name="services"
component="input"
type="checkbox"
value="Shopify build"
/>{' '}
<span css={checkboxlabel}>Shopify build</span>
</label>
</div>
<div>
<label style={{ display: 'flex', alignItems: 'center' }}>
<Field
css={checkbox}
onClick={play}
name="services"
component="input"
type="checkbox"
value="pop-up store"
/>{' '}
<span css={checkboxlabel}>Pop-up store</span>
</label>
</div>
<div>
<label style={{ display: 'flex', alignItems: 'center' }}>
<Field
css={checkbox}
onClick={play}
name="services"
component="input"
type="checkbox"
value="WebVR"
/>{' '}
<span css={checkboxlabel}>WebVR</span>
</label>
</div>
<div>
<label style={{ display: 'flex', alignItems: 'center' }}>
<Field
css={checkbox}
onClick={play}
name="services"
component="input"
type="checkbox"
value="Website audit"
/>{' '}
<span css={checkboxlabel}>Website audit</span>
</label>
</div>
<div>
<label style={{ display: 'flex', alignItems: 'center' }}>
<Field
css={checkbox}
onClick={play}
name="services"
component="input"
type="checkbox"
value="Asset creation"
/>{' '}
<span css={checkboxlabel}>Asset creation</span>
</label>
</div>
<div>
<label style={{ display: 'flex', alignItems: 'center' }}>
<Field
css={checkbox}
onClick={play}
name="services"
component="input"
type="checkbox"
value="Other"
/>{' '}
<span css={checkboxlabel}>Other</span>
</label>
</div>
</div>
<div>
<div style={{ paddingTop: '1em' }}>
<label css={label}>> Budget</label>
</div>
<Field css={budget} name="Budget" component="select">
<option />
<option value="UNDER > $3000">UNDER > $3000</option>
<option value="$3000 - $10000">$3000 - $10000</option>
<option value="$10000 - $15000">$10000 - $15000</option>
<option value="$15000 - $25000">$15000 - $25000</option>
<option value="$25000+">$25000+</option>
</Field>
<Error name="budget" />
</div>
</Wizard.Page>
<Wizard.Page>
<div>
<div>
<label css={label}>> Message</label>
</div>
<Field
css={message}
name="message"
component="textarea"
placeholder="$"
/>
<Error name="message" />
</div>
</Wizard.Page>
Wizard.js
handleSubmit = values => {
const { children, onSubmit } = this.props
const { page } = this.state
const isLastPage = page === React.Children.count(children) - 1
if (isLastPage) {
return onSubmit(values)
} else {
this.next(values)
}
}
render() {
const { children } = this.props
const { page, values } = this.state
const activePage = React.Children.toArray(children)[page]
const isLastPage = page === React.Children.count(children) - 1
return (
<Form
autocomplete="off"
initialValues={values}
validate={this.validate}
onSubmit={this.handleSubmit}
>
{({ handleSubmit, submitting, values }) => (
<form name="notypo-services" method="POST" data-netlify="true" onSubmit={handleSubmit}>
{activePage}
<div className="buttons">
{page > 0 && (
<div onClick={this.previous}>
<PrevButton></PrevButton>
</div>
)}
{!isLastPage && (
<NextButton></NextButton>
)}
{isLastPage && (
<div type="submit">
<SendButton></SendButton>
</div>
)}
</div>
</form>
)}
</Form>
)
}
Your <form> tag should have an action and the data provided should have a key-value pair:
<form name="notypo-services"
method="POST"
data-netlify="true"
action="/"
onSubmit={handleSubmit}>
And your data should be structured like:
form-name: "notypo-services"
Name: "Your typed name"
Email: "Your typed email"
Note the form-name value. It's mandatory.
If you don't have a thank-you page, you can redirect the action to himself by /.
In addition, I would suggest adding data-netlify-honeypot to avoid spam.
You can check the Netlify documentation for further details.
after days of procrastinating, I finally put this together
On submit I transfer my data into a hidden form that then gets sent over to Netlify (succesfully)
handleSubmit = values => {
const { children, onSubmit } = this.props
const { page } = this.state
const isLastPage = page === React.Children.count(children) - 1
if (isLastPage) {
document.getElementById("realFormName").value = "notypo-services";
document.getElementById("realName").value = values.Name ;
document.getElementById("realEmail").value = values.Email;
document.getElementById("realSocial").value = values.Social;
document.getElementById("realServices").value = values.Services;
document.getElementById("realBudget").value = values.Budget;
document.getElementById("realMessage").value = values.Message;
document.getElementById("myForm").submit() ;
return false ;
} else {
this.next(values)
}
}
<form id="myForm" name="notypo-services" method="POST" data-netlify="true" data-netlify-honeypot="bot-field" action="/" style={{display: 'none'}}>
<input hidden="true" name="form-name" type="text" id="realFormName" />
<input hidden="true" name="Name" type="text" id="realName" />
<input hidden="true" name="Email" type="email" id="realEmail" />
<input hidden="true" name="Social" type="text" id="realSocial" />
<input hidden="true" name="Services" type="text" id="realServices" />
<input hidden="true" name="Budget" type="text" id="realBudget" />
<input hidden="true" name="Message" type="text" id="realMessage" />
<input hidden="true" type="submit" value="Submit" />
</form>

Resources