How to make use of Radio Group with useFormik Hook - javascript

I am trying to get useFormik to validate radio groups, but it seems not to work, here is a brief example of what I am doing, whenever I submit the form after checking any of the radio input, formik throws validation error, ({currState:"you must choose property state"}), even though I choose an option.
I realized getFieldProps attaches value field to the radio, so i tried using defaultValue then react throws an error about choosing one of controlled and uncontrolled components.
import { useFormik } from "formik"
export function ListProperty(){
const { handleSubmit, getFieldProps, touched, errors } = useFormik(
{
initialValues: {
currState:"",
},
validationSchema:Yup.object().shape({
currState:Yup.string().required("you must choose property state")
}),
return (
<form onSubmit={handleSubmit} >
<div className="form-group inline">
<div className="form-control">
<input type="radio"
name="currState"
{...getFieldProps("currState")}
value="serviced"
/>
<label>serviced</label>
</div>
<div className="form-control">
<input
type="radio"
value="furnished"
name="currState"
{...getFieldProps("currState")}
/>
<label>furnished</label>
</div>
<div className="form-control">
<input
type="radio"
value="newlybuilt"
name="currState"
{...getFieldProps("currState")}
/>
<label>newly built</label>
</div>
</div>
<button type="submit">submit </button>
</form>
)
}

I gave up on the implementation with getFieldProps and did it simpler, like this:
import { useFormik } from 'formik'
export default function Component() {
const formik = useFormik({
initialValues: {
radioButtonValue: ''
},
onSubmit: values => console.log(values)
})
const handleRadioButtons = e => formik.values.radioButtonValue = e.target.value
return (
<form onSubmit={formik.handleSubmit}>
<input
type="radio"
id="one"
name="group"
value="One"
onChange={e => handleRadioButtons(e)}
required
/>
<label htmlFor="one">One</label>
<br />
<input
type="radio"
id="two"
name="group"
value="Two"
onChange={e => handleRadioButtons(e)}
/>
<label htmlFor="two">Two</label>
<button type="submit">Submit</button>
</form>
)
}
Beware, if you use formik.values.radioButtonValue value as a useEffect dependency, then setting it like this: formik.values.radioButtonValue = e.target.value not gonna trigger the change, and useEffect won't launch (at least in my case it didn't). As an alternative, you gonna have to implement some kind of condition check with this value in your useEffect code

You need to map onChange like below.
<input
type="radio"
value="furnished"
name="currState"
onChange={getFieldProps("currState").onChange}
/>

Related

How to make a form with just one input tag but multiple input fields with the use of map, keys and id

I created a form using this code using useState. But the issue is i want to make a code with lesser line and i want to create it with the use of keys and ids that uses only one single input tag in the code instead of multiple input tags. the code is mentioned below:
import './App.css';
import { useState } from "react";
function App() {
const [inputFields, setInputFields] = useState([
{
name:'',
email:'',
username:'',
password:'',
confirm:'',
mobile:''
}
])
const handelFormChange = (index, event) => {
let data = [...inputFields]
data[index][event.target.name] = event.target.value;
setInputFields(data);
}
const submit = (e) => {
e.preventDefault();
console.log(inputFields)
}
return (
<div className="App">
<form className="bg-light" onSubmit={submit}>
{/* <div className="form-group"> */}
{inputFields.map((input, index) => {
return(
<div key={index} className="form-group">
<label className="font-weight-regular"> Name </label>
<input type="name" name='name' required value={input.name} onChange={event => handelFormChange(index,event)}></input>
<label className="font-weight-regular"> Email </label>
<input type="text" name='email' required value={input.email} onChange={event => handelFormChange(index,event)}></input>
<label className="font-weight-regular"> Username </label>
<input type="text" name='username' required value={input.username} onChange={event => handelFormChange(index,event)}></input>
<label className="font-weight-regular"> Password </label>
<input type="password" name='password' required value={input.password} onChange={event => handelFormChange(index,event)}></input>
<label className="font-weight-regular"> Confirm Password </label>
<input type="password" name='confirm' required value={input.confirm} onChange={event => handelFormChange(index,event)}></input>
<label className="font-weight-regular"> Mobile Number </label>
<input type="text" name='mobile' required value={input.mobile} onChange={event => handelFormChange(index,event)}></input>
</div>
)
})}
<button onClick={submit}>Submit</button>
</form>
</div>
)
}
export default App;
So i tried to mention the make a form and i am a fresher in this field so i dont know how to make a form with single input field but i have the requirement of this code
It's possible to use a single input field to create a form with multiple inputs by using the 'name' attribute on the input field. The name attribute allows you to identify which input field the data is coming from when the form is submitted.

How to check whether all the checkboxes are checked in Reactjs?

I am new to react and I got a scenario where I have multiple checkboxes on my form. I want the user to check all the checkboxes only then enable the submit button on the form. On Load, the submit button will be disabled. How to do this?
Here is the code that I have written so far:
const MultipleCheckboxes = () => {
const handleChange = () => {
}
const allChecked = () => {
}
return (
<div>
<form>
<div className="form-check">
<input
type="checkbox"
className="some-class-name-chk"
name="someName"
value="Java"
id="languageChkDefault"
onChange={handleChange}
/>
<label
className="form-check-label"
htmlFor="languageChkDefault"
>
Javascript
</label>
</div>
<div className="form-check">
<input
type="checkbox"
className="some-class-name-chk"
name="someName"
value="Angular"
id="languageChkDefault"
onChange={handleChange}
/>
<label
className="form-check-label"
htmlFor="languageChkDefault"
>
Angular
</label>
</div>
<div className="form-check">
<input
type="checkbox"
className="some-class-name-chk"
name="someName"
value="Python"
id="languageChkDefault"
onChange={handleChange}
/>
<label
className="form-check-label"
htmlFor="languageChkDefault"
>
Python
</label>
</div> <br />
<button disabled={!allChecked}>Submit</button>
</form>
</div>
);
};
export default MultipleCheckboxes;
Can anybody help me on this? thank you
This is my solution, I hope it helps you
import { useState, useEffect } from "react";
const MultipleCheckboxes = () => {
const [allChecked, setAllChecked] = useState(false);
const [checkboxes, setCheckboxes] = useState({
javaCheckbox: false,
angularCheckbox: false,
pythonCheckbox: false
});
function handleChange(e) {
setCheckboxes({
...checkboxes,
[e.target.id]: e.target.checked
})
}
useEffect(() => {
const result = Object.values(checkboxes).every(v => v);
console.log(result);
setAllChecked(result);
}, [checkboxes]);
return (
<div>
<form>
<div className="form-check">
<input
type="checkbox"
className="some-class-name-chk"
name="someName"
value={checkboxes.javaCheckbox}
id="javaCheckbox"
onChange={handleChange}
/>
<label
className="form-check-label"
htmlFor="languageChkDefault"
>
Javascript
</label>
</div>
<div className="form-check">
<input
type="checkbox"
className="some-class-name-chk"
name="someName"
value={checkboxes.angularCheckbox}
id="angularCheckbox"
onChange={handleChange}
/>
<label
className="form-check-label"
htmlFor="languageChkDefault"
>
Angular
</label>
</div>
<div className="form-check">
<input
type="checkbox"
className="some-class-name-chk"
name="someName"
value={checkboxes.pythonCheckbox}
id="pythonCheckbox"
onChange={handleChange}
/>
<label
className="form-check-label"
htmlFor="languageChkDefault"
>
Python
</label>
</div> <br />
<button disabled={!allChecked}>Submit</button>
</form>
</div>
);
};
export default MultipleCheckboxes;
You can use react useState hook and set its default value to false.
const [state, setstate] = useState(false)
When the user clicks on an input box set the state to true. You may encounter some problems when the user unchecks the box, so you can use an if statement to handle state change
For example:
if (state === true){
setstate(false)
}else{
setstate(true)
}
or you can just use this code inside the handleChange function:
!state
It inverses the state to true/false accordingly.
After that you can use a ternary operator inside the component to check whether the user has checked all the boxes, if the user hasn't checked all the boxes, disable the button or else do otherwise.
For example, if the state is true (or in other words, if the user has checked the box), render the normal styled button, else render the disabled button:
{state? <button className = "styled"/>: <button disabled className="styled"/>}
Of course, I have only checked the state of one input box. Now you can simply check for multiple conditions by declaring multiple states for each box.
{state1 && state2 && state3 ? <button className = "styled"/>: <button disabled className="styled"/>}
If you are not yet familiar with ternary operators, you should go through this doc Ternary operators.
If you haven't heard of useState and react hooks yet, feel free to look the React's documentation. Welcome to the React ecosystem!

React Hook Form set checkbox to checked state

I am trying out React-Hook-form
The simple code for the checkbox is as below:
import React from 'react'
import { useForm } from 'react-hook-form'
export default function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm()
const onSubmit = (data: any) => console.log(data)
console.log(errors)
return (
<div className='mx-auto justify-center p-32 flex'>
<form onSubmit={handleSubmit(onSubmit)}>
<div className='p-2'>
<label htmlFor=''>January</label>
<input
type='checkbox'
placeholder='January'
{...register('January', {})}
className='mx-3'
checked
/>
</div>
<div className='p-2'>
<label htmlFor=''>February</label>
<input
type='checkbox'
placeholder='February'
{...register('February', {})}
className='mx-3'
/>
</div>
<input type='submit' />
</form>
</div>
)
}
I can submit the form correctly but I have like the January checkbox to start off as a checked box but when I put 'checked' as shown in the code, I somehow could not 'uncheck' it.
I seem to be missing something and any help would be greatly appreciated.
The issue with passing checked is that it takes control away from useForm to manage the checkbox.
Imagine the function register() returns { checked: true/false, onChange: changeHandler }. So if we where to look at the attributes this produces the following.
<input
type='checkbox'
placeholder='January'
{...register('January', {})}
className='mx-3'
checked
/>
<input
type='checkbox'
placeholder='January'
{...{
checked: true/false,
onChange: changeHandler,
}}
className='mx-3'
checked
/>
<input
type='checkbox'
placeholder='January'
checked={true/false}
onChange={changeHandler}
className='mx-3'
checked
/>
Since checked is present twice, the latter will override the former. In this case your checked is last so it overrides the value that is managed by useForm.
Passing it before the register() call won't help you either, since your default value will be overwritten by a value managed by useForm and is therefore never used.
Now that I've cleared up why this issue happens let's move on to the solution.
useForm allows you to pass a default values when you initially call the hook.
const {
register,
handleSubmit,
formState: { errors },
} = useForm({ defaultValues: { January: true } });
// ...
<input
type='checkbox'
{...register("January")}
className='mx-3'
/>
Alternatively, instead of giving each checkbox its own name, you could also use "months". If there are multiple checkboxes using the same name, the result will not be true/false, but rather an array containing the values.
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
defaultValues: { months: ["January"] }
// only January ^ is checked by default
});
//...
<input
type='checkbox'
value='January'
{...register("months")}
className='mx-3'
/>
<input
type='checkbox'
value='February'
{...register("months")}
className='mx-3'
/>
The complete working code based on #3limin4tOr
import React, { useState } from 'react'
import { useForm } from 'react-hook-form'
export default function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
defaultValues: { months: ['January'] },
})
const onSubmit = (data: any) => console.log(data)
console.log(errors)
return (
<div className='mx-auto justify-center p-32 flex'>
<form onSubmit={handleSubmit(onSubmit)}>
<div className='p-2'>
<label htmlFor=''>January</label>
<input
type='checkbox'
value='January'
placeholder='January'
{...register('months')}
className='mx-3'
/>
</div>
<div className='p-2'>
<label htmlFor=''>February</label>
<input
type='checkbox'
value='February'
placeholder='February'
{...register('months')}
className='mx-3'
/>
</div>
<input type='submit' />
</form>
</div>
)
}
You can find here input, checkbox, and radio in one field with React Hook form
import { useState } from "react";
import reactLogo from "./assets/react.svg";
import "./App.css";
import { FormProvider, useForm, useFormContext } from "react-hook-form";
const ChooseCarType = () => {
const { register } = useFormContext();
return (
<>
<div>
<label htmlFor="field-rain">
<input
{...register("weather")}
type="radio"
value="rain"
id="field-rain"
/>
Rain
</label>
<label htmlFor="field-wind">
<input
{...register("weather")}
type="radio"
value="wind"
id="field-wind"
/>
Lots of wind
</label>
<label htmlFor="field-sun">
<input
{...register("weather")}
type="radio"
value="sun"
id="field-sun"
/>
Sunny
</label>
</div>
</>
);
};
const ChooseService = () => {
const { register } = useFormContext();
return (
<>
<div>
<label>
<input type="checkbox" {...register("jan")} />
Jan
</label>
<label>
<input type="checkbox" {...register("feb")} />
Feb
</label>
<label>
<input type="checkbox" {...register("mar")} />
Mar
</label>
</div>
</>
);
};
const UserData = () => {
const { register } = useFormContext();
return (
<>
<div>
<label>
Username
<input {...register("username")} />
</label>
<label>
Password
<input {...register("password")} />
</label>
</div>
</>
);
};
function App() {
const methods = useForm();
const onSubmit = (data: any) => alert(JSON.stringify(data, null, 2));
return (
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit(onSubmit)}>
<ChooseCarType />
<ChooseService />
<UserData />
<button type="submit">Submit</button>
</form>
</FormProvider>
);
}
export default App;

Error Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'name') in React-hook-form

To validate the form, I decided to use the react-hook-form library, when you select the last name in the input in the console, an error occurs as in the screenshot. The input itself is a dadata library and I prescribe all the necessary attributes for the react-hook-form to the component, I think that's why the error occurs, what should I do? And how can this be resolved? I removed all the unimportant part of the code if that.
error screenshot
export default function Fio () {
const { register, formState: { errors } } = useForm();
const [value, setValue] = useState();
return (
<>
<span id="FIO">ФИО</span>
<FioSuggestions
token={token}
value={value}
onChange={setValue}
{...register( "fio",{required: true})}/><br/>
<div style={{height: 40}}>
{errors?.fio && <p>Error</p>}
</div>
</>
)
}
export default function Form () {
const {handleSubmit} = useForm();
const onSubmit = (data) => {
alert(JSON.stringify(data))
}
return(
<form id="formAdv" onSubmit={handleSubmit(onSubmit)}>
<Fio/>
<Birthday/><br/>
<Phone/><br/>
<label>
<input type="radio"
name="gender"
value="MALE"
/> Мужчина
<input type="radio"
name="gender"
value="FEMALE"
/> Женщина
</label><br/>
<Multiselector/><br/>
<Selector/><br/>
<label>
<input type="checkbox"/> Не отправлять СМС.
</label><br/>
<input type="submit"/>
</form>
)
}

Radio Button in stateless component in ReactJs

I'm new to react and redux and i want to create component which contain two radio buttons so i write something like this:
import React, { PropTypes } from 'react';
const renderCashRadioButtons = currentCashSelector => (
<form onClick={currentCashSelector}>
<input
type="radio"
name="cash-transaction"
value="Transcation"
onChange={value => currentCashSelector(value)}
/>
<input
type="radio"
name="cash-transfer"
value="Transfer"
onChange={value => currentCashSelector(value)}
/>
</form>
);
const CashRadioButtons = ({ currentCashSelector }) => (
<div className="container">
{renderCashRadioButtons(currentCashSelector)}
</div>
);
CashRadioButtons.propTypes = {
currentCashSelector: PropTypes.func.isRequired
};
export default CashRadioButtons;
currentCashSelector is a function. When i render this it does not seem to work. The value does not change and i'm not seeing the state to be updated. Do you have any ideas?
You probably want your radio buttons to have the same name, so that when one is selected, the other is deselected.
It looks like your onChange functions are expecting the value, but they're actually receiving the event.
You likely have unwanted duplication between the onChange on your form, and the ones on your radio buttons.
Possible Solution
<form onClick={event => currentCashSelector(event.target.value)}>
<input
type="radio"
name="cash-type"
value="Transaction"
/>
<input
type="radio"
name="cash-type"
value="Transfer"
/>
</form>

Categories

Resources