Reset a specific Input field on ant design form - reactjs

How do I reset a specific input field, in this instance, title input field?
I know how to reset all fields (using form.resetFields()) but not a specific field on ant design
<Form.Item name='Title' label='Title'>
<Input value={title} onChange={handleChange('title')} />
</Form.Item>
<Form.Item name='Category' label='Category'>
<Select
placeholder='Select a category'
style={{ width: 420 }}
onChange={handleCategoryChange}
>
{categories.length > 0 &&
categories.map((c) => (
<Option key={c._id} value={c._id}>
{c.name}
</Option>
))}
</Select>
</Form.Item>
const handleCategoryChange = (e) => {
///reset Title field
};```

You are not showing the whole form, but since you are using form.resetFields() I am assuming that you are specifying some initialValues in your form tag. Let us say you have something similar to
const initValues = {
Title: "Foo",
Category: 123,
...
}
<Form
initialValues={initvalues}
...
/>
What form.resetFields() does is set all field values back to their initialValues. What you want, then, is to reset only the title field to its initial value.
This can then be accomplished by
const handleCategoryChange = (e) => {
form.setFieldsValue( { Title: initValues.Title } )
}

Related

How to set up selected value in Select field of ant design so that it remains compatible with validation rule in reactJS?

I am using Muse Antd Design Template with antd version "antd": "^4.16.6".
I have an ant design form where I am populating data before submitting the form to edit an existing record.
currencyConversionById is the object/record I want to edit. Its structure is like this:-
currencyConversionById = {
base_currency : "USD",
base_amount : 1,
to_currency : "CAD",
to_amount : 2.45
}
currencyList is list of currencies like this:-
currencyList = [
{
currency : "American Dollar",
currency_code : "USD"
},
{
currency : "Canadian Dollar",
currency_code : "CAD"
}
]
The select field will have the currency list as its options and the option which matches with currencyConversionById.to_currency, will be displayed as selected.
This is the form:-
<Form {...layout} form={form} name={formTitle(window.location.pathname)} onFinish={onFinish}>
<Form.Item name="base_currency" label="Base Currency" rules={CURRENCY_CODE_VALIDATION}>
<Input value={baseCurrency} onChange={({ target: { value, } }) => setBaseCurrency(value)} readOnly={true}/>
</Form.Item>
<Form.Item name="base_amount" label="Base Amount">
<Input value={baseCurrencyAmount} onChange={({ target: { value, } }) => setBaseCurrencyAmount(value)} readOnly={true}/>
</Form.Item>
{
currencyListLoading
? <Loader message={"Loading Currency List"} description={"Listing all currency data"} type={"success"}/>
: <Form.Item name="toCurrency" label="To Currency" rules={[{ required: true, message: 'Please, select a secondary currency' }]} initialvalue={toCurrency}>
<Select placeholder="Select a option and change input text above" allowClear onChange={value => setToCurrency(value)} onLoad={value => setToCurrency(value)} value={toCurrency} defaultValue={toCurrency}>
<Option key={0} value="0">None</Option>
{currencyList && currencyList.length > 0 && currencyList.map((currency, indexCrn) => {
return (
<Option key={currency?.currency_code} value={currency?.currency_code}>{currency?.currency_code}</Option>
)
})}
</Select>
</Form.Item>
}
<Form.Item name="to_amount" label="To Amount" rules={AMOUNT_VALIDATION}>
<Input value={toCurrencyAmount} onChange={value => setToCurrencyAmount(value)} onLoadedData={value => setToCurrencyAmount(value)}/>
</Form.Item>
<Form.Item {...tailLayout}>
<Button type="primary" htmlType="submit">{formCardTitle(window.location.pathname)}</Button>
<Button htmlType="button" onClick={onReset}>
Reset
</Button>
</Form.Item>
</Form>
While populating the data in the form, I did this:-
useEffect(() => {
if (currencyConversionById !== null)
{
form.setFieldsValue({
base_currency : currencyConversionById?.base_currency,
base_amount : currencyConversionById?.base_amount,
to_currency : currencyConversionById?.to_currency.toString(),
to_amount : currencyConversionById?.to_amount.toString()
});
setToCurrency(currencyConversionById?.to_currency);
}
}, [currencyConversionById])
Using form.setFieldsValue I could set the values for all the text inputs, but for Select option, I had to do this:-
const [toCurrency, setToCurrency] = useState("");
useEffect(() => {
if (currencyConversionById !== null)
{
------------------------
------------------------
setToCurrency(currencyConversionById?.to_currency);
}
}, [currencyConversionById])
Using setToCurrency(), I set up toCurrency value as "CAD", and then in the form, passed it was initialValue and defaultValue like this:-
<Form.Item name="toCurrency" label="To Currency" rules={[{ required: true, message: 'Please, select a secondary currency' }]} initialvalue={toCurrency}>
<Select placeholder="Select a option and change input text above" allowClear onChange={value => setToCurrency(value)} onLoad={value => setToCurrency(value)} value={toCurrency} defaultValue={toCurrency}>
<Option key={0} value="0">None</Option>
{currencyList && currencyList.length > 0 && currencyList.map((currency, indexCrn) => {
return (
<Option key={currency?.currency_code} value={currency?.currency_code}>{currency?.currency_code}</Option>
)
})}
</Select>
</Form.Item>
By doing this, "CAD" is displayed as selected option. However, when I am trying to submit the function, the validation rule for to_currency is triggered.
Why is it happening like this? Since an option is already shown as selected, the required validation should not be fired. But don't know why this validation is keep on getting triggered.
How can I fix this?
You can use initialValues form property to set initial values
Components inside Form.Item with name property will turn into
controlled mode, which makes defaultValue not work anymore. Please try
initialValues of Form to set default value.

How to keep an option of a select element selected based on the id value fetched from the DB in ReactJS?

I am using muse ant design template. I have created a component CaptainEditForm like this:-
function CaptainEditForm({
// States
loggedInUser,
carCategoryList,
carCategoryListLoading,
carCategoryListError,
locationList,
locationListLoading,
locationListError,
userById,
userByIdLoading,
userByIdError,
// Actions
getAllCarCategories,
getAllLocations,
getUserById,
}) {
...............
...............
}
const mapState = state => ({
loggedInUser : selectorLoggedInUser(state), // loggedInUser State
carCategoryList : selectorCarCategoryList(state), // car category list State
carCategoryListLoading : selectorCarCategoryListLoading(state), // car category list loading State
carCategoryListError : selectorCarCategoryListError(state), // car category list error State
locationList : selectorLocationList(state), // location list State
locationListLoading : selectorLocationListLoading(state), // location list loading State
locationListError : selectorLocationListError(state), // location list error State
userById : selectorUserById(state), // country list State
userByIdLoading : selectorUserByIdLoading(state), // country list loading State
userByIdError : selectorUserByIdError(state), // country list error State
})
const mapDispatch = dispatch => ({
getAllCarCategories : ()=> dispatch(getAllCarCategoriesStart()), // car category data action
getAllLocations : ()=> dispatch(getAllLocationsStart()), // location data action
getUserById : (id)=> dispatch(getUserByIdStart(id)) // country data action
})
export default connect(mapState, mapDispatch)(CaptainEditForm);
In the component function, I am rendering the form like this
return (
<Form {...layout} form={form} name={formTitle(window.location.pathname)} onFinish={onFinish}>
<Form.Item name="name" label="Name" value={userById.name} rules={[{ required: true }]}>
<Input value={userById.name}/>
</Form.Item>
<Form.Item name="phone_number" label="Phone Number" rules={[{ required: true }]}>
<Input />
</Form.Item>
{
carCategoryListLoading
? <Loader message={"Loading Car Category List"} description={"Listing all car category data"} type={"success"}/>
: <Form.Item name="car_category" label="Can Handle" rules={[{ required: true }]}>
<Select mode="multiple" placeholder="Select a option and change input text above" allowClear>
<Option key={0} value="0">None</Option>
{carCategoryList && carCategoryList.length > 0 && carCategoryList.map((category, indexCat) => {
return (
<Option key={parseInt(parseInt(indexCat) + 1)} value={category.id}>{category.name}</Option>
)
})}
</Select>
</Form.Item>
}
{
locationListLoading
? <Loader message={"Loading Location List"} description={"Listing all location data"} type={"success"}/>
: <Form.Item name="location" label="Location" rules={[{ required: true }]}>
<Select placeholder="Select a option and change input text above" allowClear value={userById.locationId}>
<Option key={0} value="0">None</Option>
{locationList && locationList.length > 0 && locationList.map((locationData, indexLoc) => {
return (
<Option key={parseInt(parseInt(indexLoc) + 1)} value={locationData.id}>{locationData.name}</Option>
)
})}
</Select>
</Form.Item>
}
<Form.Item {...tailLayout}>
<Button type="primary" htmlType="submit">{formCardTitle(window.location.pathname)}</Button>
<Button htmlType="button" onClick={onReset}>
Reset
</Button>
</Form.Item>
</Form>
);
As you can see, I am having two select element, one of them is multiple.
While loading the page, I am populating the user data into the form elements via this way:-
if(typeof userById !== undefined && userById !== null)
{
form.setFieldsValue({
name: userById.name,
phone_number: userById.phoneNumber,
});
}
However, I don't know how to populate data (keep an option selected) in an select element. I tried to set the value of the Select element like this:-
location: userById.locationId
But it behaved in a weird way. The Select element started to look like a textbox with the value, ie. the id of the location being displayed.
How can I fix this?

Render data in other component when in select tag reactjs

I am using reactjs, ant design and ant design pro for my project, I have a form like the code below. Option's data is loaded from api. How can I choose that each time I select an option ,the information of that option will appear down to ProDescriptions
props.onInsertObjectFinish(value)} >
<Form.Item name="TopicId" label="ID chủ đề ">
<Input id="TopicId" type="hidden" value={currentRow?.id}/>{currentRow?.id}
</Form.Item>
<Form.Item name='ExhibitId' label="Tên hiện vật ">
<Select placeholder="Chọn hiện vật muốn thêm" style={{ width: 120 }} onSelect={(value) => props.getvalue(value)}>
{props.listObj.map((obj: any) => {
return <Option value={obj.id} >{obj.name}</Option>
})}
</Select>
<ProDescriptions
/>
</Form.Item>
</Form>
well, create a state
const [proDesc, setProDesc] = useState({});
create a function
const handleSelectChange = (value) =>{
props.getvalue(value)
let index = props.listObj.findIndex(item => item.id == value)
if(index > -1) setProDesc(props.listObj[index])
}
call function onSelectChange
onSelect={(value) => handleSelectChange(value)}
and pass this state as prop to ProDescriptions
<ProDescriptions proDesc={proDesc} />
now you have a full object of selected option in your ProDescription component, use it how ever you want
Here is the code of ProDescription that i can't using proDesc
props.onInsertObjectFinish(value)}>
<Form.Item name="TopicId" label="ID chủ đề ">
<Input id="TopicId" type="hidden" value={currentRow?.id}/>{currentRow?.id}
</Form.Item>
<Form.Item name='ExhibitId' label="Tên hiện vật ">
<Select
placeholder="Chọn hiện vật muốn thêm"
style={{ width: 120 }}
onSelect={(value) => handleSelectChange(value)}
>
{props.listObj.map((obj: any) => {
return <Option key={obj.id} value={obj.id} >{obj.name}</Option>
})}
</Select>
<ProDescriptions
column={1}
request={async () => ({
data: proDesc || {},
})}
columns={columns as ProDescriptionsItemProps<TableListItem>[]}
/>
</Form.Item>
</Form>
And here is the sample code running of ProDescription
const [currentRow, setCurrentRow] = useState();
<ProDescriptions<TableListItem>
column={1}
title={currentRow?.name}
request={async () => ({
data: currentRow || {},
})}
params={{
id: currentRow?.name,
}}
columns={columns as ProDescriptionsItemProps<TableListItem>[]}
/>

How to get boolean data from API selected in a Dropdown (REACT)?

I created a dropdown with "true" and "false" options. I get from my API all of my data in a table.
On update, I've got a form that gets the row data. With boolean values, it gets true/false just if I let the html type on "text".
I want to use the dropdown but at the moment it's static so it's always on "true".
How can I select the right value and update the change?
toSelectOption.js
export const trueFalse = [
{ label: "true", value: "Y" },
{ label: "false", value: "F" }
];
Update.jsx
renderTrueFalse() {
return trueFalse.map((item) => {
if (this.state.showKey === true) {
return (
<option value={item.value}>{item.label}</option>
);
}
});
}
//...
<Formik
initialValues={{
//...
showKey,
//...
}}
onSubmit={this.onSubmit}
//...
{
(props) => (
<Form>
//...
<Col md="3">
<FormGroup>
<label>Show Key</label>
<Field className="form-control" component="select"
name="showKey">
{this.renderTrueFalse()}
</Field>
</FormGroup>
</Col>
//...
<div className="d-flex justify-content-center">
<MDBBtn type="submit"
className="btn btn-outline-success waves-effect">Salva</MDBBtn>
</div>
</Form>
)
}
</Formik>
//...
I think that you are missing an onChange event handler on your <Field> component.
Try to add this:
Update.jsx
<Field className="form-control"
component="select"
name="showKey"
onChange={e => this.handleOnChange(e)}
>
and then below your function renderTrueFalse(), add this one:
handleOnChange = e => {
console.log('value->', e.target.value) // e.target.value is your output (Y or F) from the select option
// do whatever you wanna do here with the value from the option in this case ('Y' OR 'F')
}
Open your develop Tools (F12) and see that you are indeed receiving the updated value when you choose the right option.
Check this working on a sample with only React, here

React-Final-Form with DropDown in Child Component, how?

I'm trying to use React-final-form with a DropDown in a Child Component.
Can't get this to work.
All of my text fields are already in a Child Component and this works like a charm.
The field in the parent looks like this:
<Field
name="lastName"
placeholder="Last Name"
validate={required}
>
{({input, meta, placeholder}) => (
<MyField meta={meta} input={input} placeholder={placeholder}/>
)}
</Field>
The Child Component looks like this:
export const MyField = (props) => {
return (
<Form.Field className={props.meta.active ? 'active' : ''}>
<Label>{props.label ? props.label : props.placeholder}</Label>
<Form.Input
{...props.input}
placeholder={props.placeholder}
className={(props.meta.error && props.meta.touched ? 'error' : '')}
/>
</Form.Field>
)
};
The "Form.Field" and "Label" are coming from semantic-ui-react
But now I want to do the same with a DropDown.
The standard DropDown, taken from an example on the React-Final-Form site, looks like this:
<Field name="toppingsA" component="select">
<option value="chicken">Chicken</option>
<option value="ham">Ham</option>
<option value="mushrooms">Mushrooms</option>
<option value="cheese">Cheese</option>
<option value="tuna">Tuna</option>
<option value="pineapple">Pineapple</option>
</Field>
And it works in a sense that I'm getting the value in my react-final-form values onSubmit.
then I'm trying to offload the Dropdown itself to the Child Component (with the intention to use the semantic-ui-react version of a Dropdown, but first things first and get the Dropdown to work :-) )
Parent Component:
const eatOptions = [
{key: 'c', text: 'Chicken', value: 'chicken'},
{key: 'h', text: 'Ham', value: 'ham'},
{key: 'm', text: 'Mushrooms', value: 'mushrooms'},
{key: 't', text: 'Tuna', value: 'tuna'}
];
// And in the Form:
<Field name="toppingsB" component="select" options={eatOptions}>
{ ({input, meta, options}) => {
return (
<Opts options={options} name={input.name}/>
)
}}
</Field>
And in the Child Component:
export const Opts = (props) => {
return (
<select name={props.name}>
{props.options.map((x) => {
return (
<option key={x.key} value={x.value}>{x.text}</option>
)
})}
</select>
)
};
Result is that the HTML looks the same (which does not say that much I guess), ToppingsA is picked up in the values (on onSubmit) and ToppingsB is not.
I can't figure out what am I missing here and your help would be very much appreciated.
Thanks in advance,
Bert
If you are using render-props for toppingsB then the Field component prop should not be type "select" as the children of Field will be a function and not multiple tags.
It also looks like you are not letting your form know of any changes that occur inside the child component. Try passing the Opts component an onChange function as a prop:
<Opts
options={options}
name={input.name}
onChange={ (value:string) => input.onChange(value)}
/>
#S.Taylor, Thanks for your help!! It works.
As a reference the working code:
The Field in Parent Component:
<Field name="toppingsB" options={eatOptions} >
{ ({input, meta, options}) => {
return (
<Opts
options={options}
name={input.name}
onChange={ (value) => input.onChange(value)}
/>
)
}}
</Field>
And the code in the Child Component:
export const Opts = (props) => {
return (
<select name={props.name} onChange={props.onChange}>
{props.options.map((x) => {
return (
<option key={x.key} value={x.value}>{x.text}</option>
)
})}
</select>
)
};

Resources