I need to update the value of Form.Item manually. I have a custom component, which returns selected value, and want to pass this value to the Form for validation and so I can send it.
Is this possible with antd?
Here's the simplified code:
import { Form } from "antd";
import { FC, ReactElement, useEffect, useState } from "react";
const Child: FC<{
returnValue: (value: any) => void;
}> = ({ returnValue }): ReactElement => {
return <input onChange={(e) => returnValue(e.currentTarget.value)} />;
};
export default function App() {
const { useForm } = Form;
const [form] = useForm();
const [value, setValue] = useState<string>("");
const setNewValue = (newVal: string) => setValue(newVal);
useEffect(() => {
console.log(value);
}, [value]);
return (
<div className="App">
test
<Form form={form}>
<Form.Item
//value={value} I'm looking form smth like this
>
<Child returnValue={setNewValue} />
</Form.Item>
</Form>
</div>
);
}
And here is the code sandbox.
Using <Input> from antd will not work in my case. This is a simplified problem. I have a way more complex component, which behaves in a similar way. The returnValue is how I managed to pull the value out of the component.
For a class based component, this is how you would define a form
class CustomForm extends React.Component {
formRef = React.createRef();
constructor()
render(){
return(
<Form
ref={this.formRef}
name="customForm"
>
<Form.Item label="Email" name="email">
<Input />
</Form.Item>
</Form>
)}
}
and this is how you set form.items value
componentDidUpdate(){
this.formRef.current.setFieldsValue({
email: this.props.customerData.map((d) => d.email),
});
}
you can convert the logic for the functional component.
Related
Am new to react and i have a custom input where am handling the value and input handler via a custom hook but would like to get the value and the input handler to the parent component using the custom input but am stuck on how to achieve this.
I have written the following code.
On the custom hook
import {useReducer} from "react";
const INITAL_STATE = {value:'',valid:false,pristine:true, error:''}
const REDUCER_ACTIONS = { input:"INPUT", blur:"BLUR"}
const reducer = (state,action)=>{
if (action.type === REDUCER_ACTIONS.input){
return {...state, value: action.value}
}
if (action.type === REDUCER_ACTIONS.blur){
return {...state, pristine: false}
}
return INITAL_STATE;
}
const useForm = () => {
const [inputState, dispatch] = useReducer(reducer,INITAL_STATE)
const onBlurHandler = (event) => {
dispatch({type:REDUCER_ACTIONS.blur});
}
const onInputHandler = (event) => {
dispatch({type:REDUCER_ACTIONS.input,value:event.target.value})
}
return {
...inputState,
onBlurHandler,
onInputHandler
}
};
export default useForm;
And for my custom input i have
import useForm from "../../hooks/use-form";
const CustomInput = (props) => {
const {value, onInputHandler, onBlurHandler} = useForm(); //uses custom hook
return <>
<label htmlFor={props.id}>{props.label}</label>
<input value={value} onBlur={onBlurHandler} onInput={onInputHandler}
{...props} />
</>
}
export default CustomInput;
The above custom input has the onInput and onBlur pointing to the custom hooks since i want to reuse the functionality on other input types like select and date pickers without having to duplicate them.
On my parent component am simply calling the Custom input like
function App() {
return (
<div className="container">
<CustomInput onInputHandler={} label="First name"/>
</div>
);
}
export default App;
I would like to pass the onInputHandler and value as a props back to the parent component from the custom input but am stuck on how to do this. How do i proceed?
When you say you need to pass value, I guess you wanted to pass the initial value of the input to CustomInput. To achieve that you can pass another prop.
App.js pass initialValue to CustomInput
<CustomInput
initialValue={"abc"}
label="First name"
/>
In CustomInput pass initialValue prop to useForm hook as an argument.
const { value, onInputHandler, onBlurHandler } = useForm(props.initialValue);
Set the initialValue as the value in initial state in useForm.
const useForm = (initialValue) => {
const [inputState, dispatch] = useReducer(reducer, {
...INITAL_STATE,
value: initialValue
});
...
...
}
To pass the onInputHandler as a prop you can check if onInputHandler is available as a prop and call it along with onInputHandler coming from useForm.
In App.js defines another function that accepts event as an argument.
export default function App() {
const onInputHandler = (e) => {
console.log(e);
};
return (
<div className="App">
<CustomInput
...
onInputHandler={onInputHandler}
label="First name"
/>
</div>
);
}
In CustomInput change the onInput handler like below. You can change the logic as per your needs (I called onInputHandler in useForm and prop).
<input
value={value}
onBlur={onBlurHandler}
onInput={(e) => {
props.onInputHandler && props.onInputHandler(e);
onInputHandler(e);
}}
{...props}
/>
My approach to this will be to simply call the onInputHandler() from hooks and onInputHandler() from the props received from Parent and send the e.target.value as a prop to these functions.
const CustomInput = (props) => {
const { value, onInputHandler, onBlurHandler } = useForm(); //uses custom hook
console.log(value);
const handleInputChange = (e: any) => {
onInputHandler(e);
props.onInputHandler(e.target.value);
};
return (
<>
<label htmlFor={props.id}>{props.label}</label>
<input
value={value}
onBlur={onBlurHandler}
onInput={(e) => {
handleInputChange(e);
}}
{...props}
/>
</>
);
};
export default CustomInput;
And in the parent component we can receive them as props returned from that function and use it according to our requirement.
function App() {
return (
<div className="container">
<CustomInput
label="name"
onInputHandler={(value: string) => console.log("App",value)}
/>
</div>
);
}
export default App;
sandbox link : https://codesandbox.io/s/nifty-lamport-2czb8?file=/src/App.tsx:228-339
I have custom component which I am importing in my another Component as a Element tag. My custom Component consist of dropdown values. I want to read value the value of in my element tag when I submit my form
custom component :
import React, { useState, useMemo } from 'react'
import Select from 'react-select'
import countryList from 'react-select-country-list'
function CountrySelector() {
const [value, setValue] = useState('')
const options = useMemo(() => countryList().getData(), [])
const changeHandler = value => {
setValue(value)
}
return <Select options={options} value={value} onChange={changeHandler} />
}
export default CountrySelector
i want to use that custom component country selector values on my submit button:
main component:
import react from 'react';
import CountrySelector from '../../helpers/CountrySelector';
import IdType from '../../helpers/IdType';
import ProofOfAddress from '../../helpers/ProofOfAddress';
const submitForm=(e)=>{
//debugger;
e.preventDefault();
console.warn(e.target)
};
const IdentityVerification = (props) => {
const saveUser=(e)=>{
console.warn({e});
}
return (
<form onSubmit={submitForm} >
<div className='app'>
<label >Choose Issuing Country/region</label>
<CountrySelector/>
<label >Select ID Type</label>
<IdType/>
<label >Proof of Address</label>
<ProofOfAddress/>
</div>
<div className="form-actions">
<button >Submit</button>
</div>
</form>
);
};
export default IdentityVerification;
how can i read values?
The normal way to handle this would be to move the state and your changeHandler function into the parent component and pass the handler down to the child as a prop.
const IdentityVerification = (props) => {
const [value, setValue] = useState('')
const changeHandler = value => {
setValue(value)
}
return (
// ...
<CountrySelector onChange={changeHandler}/>
// ...
);
and in your child:
function CountrySelector({changeHandler}) {
// ....
return <Select options={options} value={value} onChange={changeHandler} />
}
I have an object that is outputted from the reactIcons npm package https://www.npmjs.com/package/react-icons I am importing everything from one of the folders with import * as ReactIcons from 'react-icons/fa' I am using sanity studio, I created a text input that takes the value searched and runs a search function that runs a includes on the values from the object I grabbed from the reactIcons fa folder and log's the vales that match. Now I want to take those values and update a react component with useState() Howerver I get the following error Uncaught ReferenceError: setIcon is not defined and SetIcon is the setter function from useState array. Here is my code so far
import React, { useState } from 'react';
import PropTypes from 'prop-types'
import FormField from 'part:#sanity/components/formfields/default'
import PatchEvent, {set, unset} from 'part:#sanity/form-builder/patch-event'
import * as ReactIcons from 'react-icons/fa'
console.log(ReactIcons);
const createPatchFrom = value => PatchEvent.from(value === '' ? unset() : set(String(value)))
const Example = value => {
const [icon, setIcon] = useState();
return (
<div>{icon}</div>
);
}
const search = value => {
console.log(value);
Object.keys(ReactIcons).map(go => {
if (go.toLowerCase().includes(value) === true){
console.log(go);
setIcon(go);
}
})
}
class IconPickerCustom extends React.Component{
static propTypes = {
value: PropTypes.string,
onChange: PropTypes.func.isRequired
};
render = () =>{
const {type, value, onChange} = this.props
return (
<>
<FormField label={type.title} description={type.description}>
<input
type="text"
value={value === undefined ? '' : value}
onChange={event => onChange(createPatchFrom(event.target.value))}
ref={element => this._inputElement = element}
/>
</FormField>
<input
type="text"
onChange={event => search(event.target.value)}
/>
{Object.values(ReactIcons).map(X =>{
return (
<>
<X/>
</>
);
})}
{console.log(ReactIcons.Fa500Px)}
<ReactIcons.Fa500Px/>
<Example/>
</>
)
}
}
export default IconPickerCustom;
React has two types of components, class components and function components (formerly stateless components). Hooks are used in function components when you realize you need state inside a function component and prefer not to convert it to a class component.
The useState() Hook allows us to add state in a function component.
Class Component
//initialize state
constructor(props) {
super(props);
this.state = {foo: bar};
}
//set state
this.setState({foo: baz});
//read state
this.state.foo;
Function Component
(with useState() Hook)
//initialize state
const [icon, setIcon] = useState("myInitialValue");
//set state
setIcon("myNewValue");
//read state
{icon}
That being said, you already have a class component so no need to use hooks here.
class IconPickerCustom extends React.Component{
constructor(props) {
super(props);
this.state = { icon: "nothing" };
}
static propTypes = {
value: PropTypes.string,
onChange: PropTypes.func.isRequired
};
const createPatchFrom = value => PatchEvent.from(value === '' ? unset() : set(String(value)));
const search = value => {
Object.keys(ReactIcons).map(go =>
({ go.toLowerCase().includes(value) ?
this.setState({icon:go}) : null;})
}
render = () =>{
const {type, value, onChange} = this.props
return (
<>
<FormField label={type.title} description={type.description}>
<input
type="text"
value={value === undefined ? '' : value}
onChange={event => onChange(createPatchFrom(event.target.value))}
ref={element => this._inputElement = element}
/>
</FormField>
<input
type="text"
onChange={event => search(event.target.value)}
/>
{Object.values(ReactIcons).map(X =>{
return (
<>
<X/>
</>
);
})}
{console.log(ReactIcons.Fa500Px)}
<ReactIcons.Fa500Px/>
<Example/>
</>
)
}
}
export default IconPickerCustom;
You are going to want something along those lines. Let me know if you have any questions.
I am using the material-ui and redux-form to control a web form with multiple checkboxes, what I excepted is when ticking the checkbox, it will dispatch an action to update the value(language:['English'] -> language: ['English', 'Spanish']) in redux-form rather than adding a new attribute (such as Spanish:true), the issue could be I register different Files for per language,
Could anyone help?
Here is the screenshot of checkboxes
Here is the code:
checkbox
import React from 'react';
import { Field } from 'redux-form';
import Checkbox from '#material-ui/core/Checkbox';
import FormControlLabel from '#material-ui/core/FormControlLabel';
const renderCheckbox = ({ input, label }) => (
<div>
<FormControlLabel
control={<Checkbox checked={!!input.value} onChange={input.onChange} />}
label={label}
/>
</div>
);
export class FormCheckbox extends React.Component {
render() {
const { languages, label } = this.props;
return (
<>
<div>
{languages.map((language, index) => (
<Field
key={index}
name={language.name}
label={language.name}
component={renderCheckbox}
/>
))}
</div>
</>
);
}
}
index.js
const languages = ['Spanish', Norwegian]
<FormCheckbox
name={'languages'}
label={'configuration.agent.language'}
languages={languages}
/>
const mapStateToProps = (state, ownProps) => ({
initialValues: {language: ['English']}
const mapDispatchToProps = dispatch => ({});
let Form = reduxForm({
form: 'SelectForm',
enableReinitialize: 'true',
})(Form);
how to solve this problem?
I am trying to make a set of questions through multiple pages, so I need the selected answer from page 1 and page 2 to be passed to page 3 because page 3 is like the confirmation page which will show all the selected answer from the past 2 pages.
The interface is successfully shown, well, easy but it seems like there is no data passed at all, oh, and the types of questions are radio and checkbox, so it's kinda hard for me because these 2 types are something new for me (if textarea or normal input, is easy).
This is the mainpage.jsx
// MainForm.jsx
import React, { Component } from 'react';
import AircondQuantity from './AircondQuantity';
import ServicePackage from './ServicePackage';
import Confirmation from './Confirmation';
import Success from './Success';
class MainForm extends Component {
state = {
step: 1,
oneAircond: ''
}
nextStep = () => {
const { step } = this.state
this.setState({
step : step + 1
})
}
prevStep = () => {
const { step } = this.state
this.setState({
step : step - 1
})
}
handleChange = input => event => {
this.setState({ [input] : event.target.value })
}
render(){
const {step} = this.state;
const { oneAircond } = this.state;
const values = { oneAircond };
switch(step) {
case 1:
return <AircondQuantity
nextStep={this.nextStep}
handleChange = {this.handleChange}
values={values}
/>
case 2:
return <ServicePackage
nextStep={this.nextStep}
prevStep={this.prevStep}
handleChange = {this.handleChange}
values={values}
/>
case 3:
return <Confirmation
nextStep={this.nextStep}
prevStep={this.prevStep}
values={values}
/>
case 4:
return <Success />
}
}
}
export default MainForm;
this is the first page, AircondQuantity.jsx
// AircondQuantity.jsx
import React, { Component } from 'react';
import { Form, Button, FormRadio, Radio } from 'semantic-ui-react';
class AircondQuantity extends Component{
saveAndContinue = (e) => {
e.preventDefault()
this.props.nextStep()
}
render(){
const { values } = this.props;
return(
<Form >
<h1 className="ui centered"> How many aircond units do you wish to service? </h1>
<Form.Field>
<Radio
label='1'
name='oneAircond'
value='oneAircond'
//checked={this.state.value === this.state.value}
onChange={this.props.handleChange('oneAircond')}
defaultValue={values.oneAircond}
/>
</Form.Field>
<Button onClick={this.saveAndContinue}> Next </Button>
</Form>
)
}
}
export default AircondQuantity;
this is the next page, ServicePackage.jsx
// ServicePackage.jsx
import React, { Component } from 'react';
import { Form, Button, Checkbox } from 'semantic-ui-react';
import { throws } from 'assert';
class ServicePackage extends Component{
saveAndContinue = (e) => {
e.preventDefault();
this.props.nextStep();
}
back = (e) => {
e.preventDefault();
this.props.prevStep();
}
render(){
const { values } = this.props
return(
<Form color='blue' >
<h1 className="ui centered"> Choose your package </h1>
<Form.Field>
<Checkbox
label={<label> Chemical Cleaning </label>} />
</Form.Field>
<Form.Field>
<Checkbox
label={<label> Deep Cleaning </label>} />
</Form.Field>
<Button onClick={this.back}> Previous </Button>
<Button onClick={this.saveAndContinue}> Next </Button>
</Form>
)
}
}
export default ServicePackage;
this is the confirmation.jsx page, the page that will show all the selected options
// Confirmation.jsx
import React, { Component } from 'react';
import { Button, List } from 'semantic-ui-react';
import AircondQuantity from './AircondQuantity';
class Confirmation extends Component{
saveAndContinue = (e) => {
e.preventDefault();
this.props.nextStep();
}
back = (e) => {
e.preventDefault();
this.props.prevStep();
}
render(){
const {values: { oneAircond }} = this.props;
return(
<div>
<h1 className="ui centered"> Confirm your Details </h1>
<p> Click Confirm if the following details have been correctly entered </p>
<List>
<List.Item>
<List.Content> Aircond Quantity: {oneAircond}</List.Content>
</List.Item>
</List>
<Button onClick={this.back}>Back</Button>
<Button onClick={this.saveAndContinue}>Confirm</Button>
</div>
)
}
}
export default Confirmation;
I am very new in using React and I know that I have some mistakes in transferring values or variables but I can't detect it, coz I am a newbie, so em, can you help me? thank you.
This doesn't look right to me:
onChange={this.props.handleChange('oneAircond')}
Firstly, it's going to be called instantly, before onChange is actually called, to fix that do this:
onChange={() => this.props.handleChange('oneAircond')}
However you'll also need to pass the change event from the radio button, try this:
onChange={(event) => this.props.handleChange('oneAircond')(event)}
The handleChange function below is a function that returns another function, the first one taking the 'oneAircond' string (input) and returning a function that is expecting the event from the radio button to be passed which is what you're missing
handleChange = input => event => {
this.setState({ [input] : event.target.value })
}
Ok, first i convert solution into hooks:
// MainForm.jsx
import React, { Component, useState, useEffect } from 'react';
import AircondQuantity from './AircondQuantity';
import ServicePackage from './ServicePackage';
import Confirmation from './Confirmation';
// import Success from './Success';
let MainForm = (props) => {
const [step, setStep] = useState(1)
const [input, setInput] = useState([])
const [oneAircond, setoneAircond] = useState('')
const nextStep = () => {
setStep(step + 1)
}
const prevStep = () => {
setStep(step - 1)
}
const handleChange = input => event => {
setInput({ [input] : event.target.value})
console.log(input)
}
const values = { oneAircond };
return(
<React.Fragment>
{(() => {
switch(step) {
case 1:
return <AircondQuantity
nextStep={nextStep}
handleChange = {handleChange}
values={values}
/>
case 2:
return <ServicePackage
nextStep={nextStep}
prevStep={prevStep}
handleChange = {handleChange}
values={values}
/>
case 3:
return <Confirmation
nextStep={nextStep}
prevStep={prevStep}
values={values}
/>
case 4:
// return <Success />
}
})()}
</React.Fragment>
)
}
export default MainForm;
Next I transform AirCondQuantity.jsx, and create new component Radio.jsx, which holds Radio structure (it is a component into which we inject data directly)
So here is:
// AircondQuantity.jsx
import React, { Component, useState } from 'react';
import { Form, Button, FormRadio, } from 'semantic-ui-react';
import Radio from './Radio';
let AircondQuantity = (props) => {
const [radio, setRadio] = useState();
const radioSelect = (name, e) => {
localStorage.setItem('FirstStep', name);
setRadio({ selectedRadio: name })
console.log(radio)
}
const saveAndContinue = (e) =>{
e.preventDefault()
props.nextStep()
}
return(
<Form >
<h1 className="ui centered"> How many aircond units do you wish to service? </h1>
<Form.Field>
<Radio
handleRadioSelect={radioSelect}
selectedRadio={radio}
name ="oneAircond"/>
<Radio
handleRadioSelect={radioSelect}
selectedRadio={radio}
name ="twoAircond"/>
</Form.Field>
<Button onClick={saveAndContinue}> Next </Button>
</Form>
)
}
export default AircondQuantity;
I added function, which setting the item to LocalStorage + send it in radio state
Additional here is a Radio component:
import React, { Component, useState } from 'react';
const Radio = (props) => {
return (
<div className = "RadioButton"
onClick={() => props.handleRadioSelect(props.name)} >
<div>
<input id={props.id} value={props.value} type="radio" checked={props.selectedRadio === props.name} />
{props.name}
</div>
</div>
);
}
export default Radio;
The solution works, despite one thing - it doesn't check the box, I have no idea how to fix it.