Rendering text of one input field to another in Ant Design - javascript

I am using ant design and I have 2 input fields Enter Example and Select Value now when I select text from Enter Example the selected text should get rendered inside the Select Value field
For selecting the highlighted text I am using window.getSelection().toString() and when I console I am getting the selected text value but how can I display that inside the Select Value Input Field
Problem :- How to render the selected text of Enter Example Input Field inside Select Value Input Field
What I have tried :-
const ExampleComponent = (props) => {
const [exampleValue,setExampleValue] = useState('')
const handleMouseUp = () => {
const selectedTextValue = window.getSelection().toString()
setExampleValue(selectedTextValue)
console.log(selectedTextValue)
}
return (
<Form
form={form}
labelCol={{ span: 7 }}
wrapperCol={{ span: 10 }}
layout="horizontal"
colon={true}
onFinish={onFinish}
size="large"
>
<Form.Item
label="Enter Example"
name="example_name"
className="csi-ant-form-item"
hasFeedback
rules={[
{ required: true, message: "This Field Cannot be Empty!" },
({ getFieldValue }) => ({
validator(_, value) {
if (value.length < 4) {
return Promise.reject("Length too short");
}
return Promise.resolve();
},
}),
]}
>
<AutoComplete>
<Input allowClear onMouseUp={handleMouseUp}/>
</AutoComplete>
</Form.Item>
<Form.Item
label="Select Value"
name="entity_value"
className="csi-ant-form-item"
hasFeedback
rules={[
{ required: true, message: "This Field Cannot be Empty!" },
]}
>
<AutoComplete>
<Input placeholder="Select Value from Example" value={exampleValue}/>
</AutoComplete>
</Form.Item>
</Form>
)
}
I am trying to display the highlighted text using the value prop like value ={exampleValue}

Related

Antd with formik setFieldValue

There is a Antd table with data, when i click to button "Change", the entire line with data is passed to the function in the form of an object, now it remains to insert data into the fields, but I can't, what should I do?
How set data to antd input using outside function?
I can do it with .map (), but it seems more appropriate to me to use formik
const BankForm = (props) => {
const [form] = Form.useForm();
//show close form
const columns = [
...MY columns
{
title: "Действие",
key: "action",
fixed: "right",
render: (text, record) => (
<Space size="middle"
I clink to Button and all data of row go to ChangeBank(record)
<a onClick={() => ChangeBank(record)}> Изменить</a>
</Space>
),
},
];
const formik = useFormik({
initialValues: {
name_bank: "",
},
validate,
onSubmit: (values) => {
},
});
//my function to set data to form
let ChangeBank = (record) => {
formik.setFieldValue("name_bank", record.name_bank);
};
return (
<div className={clas.tableBlock_header}>
my form
<Form
form={form}
layout="vertical"
hideRequiredMark
onFinish={formik.handleSubmit}
>
<Form.Item
name="name_bank"
label="Название банка"
rules={[{ required: true, message: "Введите название банка" }]}
>
<Input value={formik.values.name_bank} name="name_bank" />
</Form.Item>
</Form>
);
};
If you want to set values in antd form fields with formik, dont give the name Form.item
AND if you want use antd with formik, and you need validaite your inputs just download Yup. Dont use antd menthods.
Yup with formik
<Form
form={form}
layout="vertical"
hideRequiredMark
onFinish={formik.handleSubmit}
>
<Form.Item
label="Название банка"
rules={[{ required: true, message: "Введите название банка" }]}
>
<Input value={formik.values.name_bank} name="name_bank" />
</Form.Item>
</Form>**strong text**

Update Select Option list based on other Select field selection ant design

<Form
layout="vertical"
size="medium"
className="test-form"
requiredMark={false}
onFinish={onFinish}
>
<Form.Item
name="companyId"
label="Company/Customer"
rules={[{ required: true, message: "Please select Company!"}]}
>
<Select
onChange={this.handleSelectCompanyOnchange}
style={{ width: "50%" }}
name="companyId"
>
{users.map((user, index) => {
return (
<Option key={index} value={user.companyID}>
{user.companyName}
</Option>
);
})}
</Select>
</Form.Item>
<Form.Item
label="Products"
name="products"
rules={[{ required: true, message: "Please select Products!"}]}
>
<Select mode="multiple" allowClear style={{ width: "70%" }}>
{products.map((product, index) => {
if (this.state.companyId == product.companyId) {
return (
<Option key={index} value={product.id}>
{product.productName}
</Option>
);
}
})}
</Select>
</Form.Item>
</Form>
I am trying to achieve Options in Products Select element changes according to the Company Select onChange selection.
I have specified onChange in Select and calling this.handleSelectCompanyOnchange. In which I get selected companyId.
In this.state.companyId I had set companyId manually which I will remove.
I am really new to ant design and not able to figure out how to update the Products list once Company is selected.
Here, users and products are json as below.
users:
[{
companyID: 2
companyName: "TEST1"
},{
companyID: 7
companyName: "TEST2"
}]
products:
[{
companyId: 2
id: 1
productName: "TESTProduct1"
},{
companyId: 7
productName: "TESTProduct2"
id: 2
},{
companyId: 7
id: 3
productName: "TESTProduct3"
},{
companyId: 7
id: 4
productName: "TESTProduct4"
}]
However, I have tried getValueFromEvent but not able to achieve this. I am using Ant design Form and Select for this. Also I did referred to https://github.com/ant-design/ant-design/issues/4862 and how to get field value on change for FormItem in antd
Here is what you need to achieve it.
Use onValuesChange prop of the Form. This is the best place to perform setState when it comes to antd Form field changes, not on Select or Input onChange.
<Form onValuesChange={handleFormValuesChange}>
...
</Form>
A form instance (hook). This is optional in your case, but this is useful on setting and getting form values. See more here about it.
const [form] = Form.useForm();
<Form form={form} onValuesChange={handleFormValuesChange}>
...
</Form>
This is the product options render looks like, a combination of map and filter where selectedCompanyId comes from state. Take note that don't use index as key if the fixed length of the list is unknown, the react will confuse on this and you will get some logical error. Use some unique id.
<Form.Item label="Products" name="product">
<Select>
{products
.filter((product) => product.companyId === selectedCompanyId)
.map((product) => (
<Option key={product.id} value={product.id}>
{product.productName}
</Option>
))}
</Select>
</Form.Item>
And here is the handleFormValuesChange
const handleFormValuesChange = (changedValues) => {
const formFieldName = Object.keys(changedValues)[0];
if (formFieldName === "company") {
setSelectedCompanyId(changedValues[formFieldName]); // perform setState here
form.setFieldsValue({product: undefined}) //reset product selection
}
};
Here is the complete working code in react hooks:
the idea here is that you only need to watch the value change in the state.
For example, your select should "watch" a value of state and then you can easily update the state via its own setState method of React. Inside of an onChange event, you can simply just do something with our state.
<Select
value={state.productId}
onChange={e => {// Do something}}
>
{...}
<Select/>
Below is my example code how did I update the day every time I reselect week selection. Hopefully that this can help you.
import { Divider, Select } from 'antd';
import React, { useState } from 'react';
export function Example(): JSX.Element {
const [state, setState] = useState<{week: number, day: number}>({
day: 1,
week: 1
});
const weeks = [1,2,3,4];
const days = [1,2,3,4,5];
return <>
<Select
value={state.week}
onChange={(value) => setState({ week: value, day: 1})}
>
{
weeks.map(week => {
return <Select.Option
key={week}
value={week}
>
{week}
</Select.Option>;
})
}
</Select>
<Divider/>
<Select
value={state.day}
onChange={(value) => setState({...state, day: value})}
>
{
days.map(day => {
return <Select.Option
key={day}
value={day}
>
{day}
</Select.Option>;
})
}
</Select>
</>;
}
Lets say you want to update your option list based on data you get from backend;
note:categories is an array object. From this array you take out label and value for each option, see below:
const newOptions = categories.map((item, index) => {
return {
label: item.name,
value: item._id,
};
});
Then use newOptions inside your form like that:
<Form.Item label="anyName" name="anyName">
<Select style={{ width: 220 }} onChange={ handleChange } options={ newOptions } />
</Form.Item>

Display input fields based on a variable number in state

I have the below piece of code. I have defined a const in state called items. This is the dropdown selection. It has value 0, 1 and 2 and these indicate no. of dependents.
Once user selects this dropdown, i then update the value of selected dropdown in dependents constant using useState.
I want to display input field below this which will allow user to enter dependents age. For e.g. user selects 2 in dropdown. I want to show 2 input fields below which will allow user to enter the age of 2 dependents. Similarly, if i select 1- i should only show 1 input field. In that way it should show dynamically the number of input fields as user selects in dropdown.
Can someone please let me know how to achieve it.
function App() {
const [items] = useState([
{ label: "0", value: "0" },
{ label: "1", value: "1" },
{ label: "2", value: "2" }
]);
const [dependents, setDependents] = useState("0");
return (
<div className="App">
Select Dependents:
<select onChange={e => setDependents(e.currentTarget.value)}>
{items.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))
}
</select>
</div>
);
}
"
Create an array based on the selected value and map it to render the input:
<div className="App">
Select Dependents:
<select onChange={e => setDependents(e.currentTarget.value)}>
{items.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))
}
</select>
{[...Array(+dependents)].map((_,index)=>{
return <input type="text" key={index} />
})
}
</div>
Note :
[...Array(number)] creates an array of undefined items with length equals to number, and +number converts a string to number like +"4" gives 4

Unable to show helperText once we click on the Submit button using reactjs?

I'm new to this dropdown validations, i want to show helpertext bottom of the dropdown when the dropdown field is selected (or) we have selected but again selected the -1 menu item value. Here I'm facing few issues.
Couldn't able to show red color for helpertext.
For me, it is showing error in line #50 but in Sandbox it is not showing any error.
While submitting form with empty dropdown field(-1) then it should show helpertext.
I could not able to show the Helper Text while submitting the form.
Here i have tried in this way:
class Sample extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
channel: -1,
sports: -1,
movie: ""
};
}
handleChange = (e: any) => {
this.setState({ channel: e.target.value });
};
handleSports = (e: any) => {
this.setState({ sports: e.target.value });
};
handleMovie = (e: any) => {
this.setState({ movie: e.target.value });
};
Valid = () => {
const errors = { channel: "", sports: "", movie: "" };
if (!this.state.channel) {
errors.channel = "Please select channel";
}
if (!this.state.sports) {
errors.sports = "select Sports";
}
if (!this.state.movie) {
errors.movie = "select movie";
}
return {
errors,
isSubmit: Object.keys(errors).length === 0
};
};
handleSubmit = (e: any) => {
e.preventDefault();
const data = {
channel: this.state.channel,
sports: this.state.sports,
movie: this.state.movie
};
console.log(data);
};
render() {
const { errors, isSubmit } = this.Valid();
return (
<>
<FormControl>
<Select
defaultValue={-1}
onChange={this.handleChange}
displayEmpty
inputProps={{ "aria-label": "Without label" }}
>
<MenuItem value={-1}>Select Channel</MenuItem>
<MenuItem value={10}>Sports</MenuItem>
<MenuItem value={20}>Entertainment</MenuItem>
</Select>
{!this.state.channel ? (
<FormHelperText>{errors.channel}</FormHelperText>
) : null}
</FormControl>
{this.state.channel === 10 ? (
<div>
<FormControl>
<Select
defaultValue={-1}
onChange={this.handleSports}
displayEmpty
inputProps={{ "aria-label": "Without label" }}
>
<MenuItem value={-1}>Select </MenuItem>
<MenuItem value={10}>Star sports 1</MenuItem>
<MenuItem value={20}>Star sports 2</MenuItem>
</Select>
{!this.state.sports ? (
<FormHelperText>{errors.sports}</FormHelperText>
) : null}
</FormControl>
</div>
) : this.state.channel === 20 ? (
<div>
<FormControl>
<Select
defaultValue={-1}
onChange={this.handleMovie}
displayEmpty
inputProps={{ "aria-label": "Without label" }}
>
<MenuItem value={-1}>Select</MenuItem>
<MenuItem value={10}>Star Movies</MenuItem>
<MenuItem value={20}>ABC</MenuItem>
</Select>
{!this.state.movie ? (
<FormHelperText>{errors.movie}</FormHelperText>
) : null}
</FormControl>
</div>
) : null}
<div>
<Button disabled={isSubmit} onClick={this.handleSubmit}>
Submit
</Button>
</div>
</>
);
}
}
export default Sample;
Here is the sample
Can anyone please help me with this query?
Issue 1
Couldn't able to show red color for helpertext.
You can color the text red by using the error prop on the FormControl or FormHelperText. The FormControl actually provides a context to the fields it wraps so it's easiest to set the error prop there.
<FormControl error={!!errors?.channel}>
...
{errors?.channel && <FormHelperText>{errors.channel}</FormHelperText>}
</FormControl>
Issue 2
For me, it is showing error in line #50 but in Sandbox it is not
showing any error.
Unfortunately without any more context about what line 50 consists of locally for you there's not much to resolve here. Feel free to update your question with more details, perhaps a code snippet of the offending line and the copy of the error message.
Issue 3
While submitting form with empty dropdown field(-1) then it should
show helpertext.
Here I think a bit of a refactor is in order.
Disable the first "placeholder" select option, it should really be selectable, but it can still be the defaultValue. What this means is that once a valid option is selected, only other valid options can be selected, it can never select the disabled option. This also means that the field is only invalid while a user has not chosen any option.
<MenuItem disabled value={-1}>
Select Channel
</MenuItem>
<MenuItem value={10}>Sports</MenuItem>
<MenuItem value={20}>Entertainment</MenuItem>
You've 2 levels of select fields. When a user changes the root channel state, reset the movie and sports states.
Change the state shape to include some error/validation object that will hold errors and form submittable status. Reset when state updates.
componentDidUpdate(prevProps, prevState) {
// If channel updated then reset "nested" select values
if (prevState.channel !== this.state.channel) {
this.setState({
sports: null,
movie: null
});
}
// Clear error state upon change, next validation to occur next submit attempt
if (!prevState.validation.canSubmit && !this.state.validation.canSubmit) {
this.setState({
validation: {
canSubmit: true
}
});
}
}
Add name attributes to the select inputs to be accessed in the onChange handlers; these should match the names in state. Also, because you have a name, you can reduce the onChange handlers down to a single input change handler.
<Select
defaultValue={-1}
onChange={this.handleChange}
displayEmpty
inputProps={{ "aria-label": "Without label" }}
name="channel" // <-- add name attribute (add for other inputs as well)
>
handler
handleChange = (e: any) => {
const { name, value } = e.target;
this.setState({ [name]: value } as Pick<
State,
"channel" | "movie" | "sports"
>);
};
Since it isn't possible to select sports AND movie, use some branching logic to validate one or the other depending on channel, i.e. if sports is expected to have a value then movie will never have a value, and vice-versa.
Valid = ({ channel, sports, movie }): Validation => {
const errors: Errors = {};
if (!channel) {
errors.channel = "Please select channel";
} else {
if (channel === 10) {
if (!sports) {
errors.sports = "select Sports";
}
} else {
if (!movie) {
errors.movie = "select movie";
}
}
}
return {
errors,
canSubmit: !Object.keys(errors).length
};
};
Move the form validation to the onSubmit handler, disable the submit button if the validation "canSubmit" status is false.
handleSubmit = (e: any) => {
e.preventDefault();
const { channel, movie, sports } = this.state;
const validation = this.Valid({ channel, movie, sports });
if (validation.canSubmit) {
window.alert("SUBMIT!!");
} else {
console.log("errors", validation.errors);
this.setState({ validation });
}
};
Fullcode
I'll apologize ahead of time as I have very little to no typescript experience. Just some quick reading up on syntax. The following has zero errors/warnings in the linked sandbox.
import React from "react";
import {
FormControl,
Select,
MenuItem,
FormHelperText,
Button
} from "#material-ui/core";
interface Props {}
interface Errors {
channel?: string;
sports?: string;
movie?: string;
}
interface Validation {
errors?: Errors;
canSubmit: boolean;
}
interface State {
channel: number;
sports: number;
movie: string;
validation: Validation;
}
class Sample extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
channel: null,
sports: null,
movie: null,
validation: {
canSubmit: true
}
};
}
componentDidUpdate(prevProps, prevState) {
// If channel updated then reset "nested" select values
if (prevState.channel !== this.state.channel) {
this.setState({
sports: null,
movie: null
});
}
// Clear error state upon change, next validation to occur next submit attempt
if (!prevState.validation.canSubmit && !this.state.validation.canSubmit) {
this.setState({
validation: {
canSubmit: true
}
});
}
}
handleChange = (e: any) => {
const { name, value } = e.target;
this.setState({ [name]: value } as Pick<
State,
"channel" | "movie" | "sports"
>);
};
Valid = ({ channel, sports, movie }): Validation => {
const errors: Errors = {};
if (!channel) {
errors.channel = "Please select channel";
} else {
if (channel === 10) {
if (!sports) {
errors.sports = "select Sports";
}
} else {
if (!movie) {
errors.movie = "select movie";
}
}
}
return {
errors,
canSubmit: !Object.keys(errors).length
};
};
handleSubmit = (e: any) => {
e.preventDefault();
const { channel, movie, sports } = this.state;
const validation = this.Valid({ channel, movie, sports });
if (validation.canSubmit) {
window.alert("SUBMIT!!");
} else {
console.log("errors", validation.errors);
this.setState({ validation });
}
};
render() {
const {
validation: { canSubmit, errors }
} = this.state;
return (
<>
<FormControl error={!!errors?.channel}>
<Select
defaultValue={-1}
onChange={this.handleChange}
displayEmpty
inputProps={{ "aria-label": "Without label" }}
name="channel"
>
<MenuItem disabled value={-1}>
Select Channel
</MenuItem>
<MenuItem value={10}>Sports</MenuItem>
<MenuItem value={20}>Entertainment</MenuItem>
</Select>
{errors?.channel && <FormHelperText>{errors.channel}</FormHelperText>}
</FormControl>
{this.state.channel === 10 && (
<div>
<FormControl error={!!errors?.sports}>
<Select
defaultValue={-1}
onChange={this.handleChange}
displayEmpty
inputProps={{ "aria-label": "Without label" }}
name="sports"
>
<MenuItem disabled value={-1}>
Select{" "}
</MenuItem>
<MenuItem value={10}>Star sports 1</MenuItem>
<MenuItem value={20}>Star sports 2</MenuItem>
</Select>
{errors?.sports && (
<FormHelperText>{errors.sports}</FormHelperText>
)}
</FormControl>
</div>
)}
{this.state.channel === 20 && (
<div>
<FormControl error={!!errors?.movie}>
<Select
defaultValue={-1}
onChange={this.handleChange}
displayEmpty
inputProps={{ "aria-label": "Without label" }}
name="movie"
>
<MenuItem disabled value={-1}>
Select
</MenuItem>
<MenuItem value={10}>Star Movies</MenuItem>
<MenuItem value={20}>ABC</MenuItem>
</Select>
{errors?.movie && (
<FormHelperText error>{errors.movie}</FormHelperText>
)}
</FormControl>
</div>
)}
<div>
<Button disabled={!canSubmit} onClick={this.handleSubmit}>
Submit
</Button>
</div>
</>
);
}
}
export default Sample;

Ant Design reset select

I have 2 <Select>'s. The values in the second are dependant on the selection made on the first. When I change the selected item in the first, the available options on the second update. But if I already have a selection made on the second, that option remains selected even if it isn't supposed to be available based on a change to the first select.
How can I reset the second select to have nothing selected when a change is made to the first select?
First Select:
<FormItem {...formTailLayout}>
<FormTitle>Operation</FormTitle>
{getFieldDecorator('Operation', {
rules: [
{
required: true
}
]
})(
<Select
showSearch
placeholder="Select an option"
onChange={this.handleOperationChange}
>
{operations.map(operation => (
<Option value={operation.operation_id}>
{operation.operation_name}
</Option>
))}
</Select>
)}
</FormItem>
Second Select:
<FormItem {...formTailLayout}>
<FormTitle>Metric</FormTitle>
{getFieldDecorator('Metric', {
rules: [
{
required: true
}
]
})(
<Select
showSearch
placeholder="Select an operation first"
onChange={this.handleMetricChange}
>
{matrics
.filter(
metric => metric.operation_fk === operation_fk
)
.map(metric => (
<Option value={metric.metric_name}>
{metric.metric_name}
</Option>
))}
</Select>
)}
</FormItem>
You need to take a look at Coordinated Controls example mentioned on ant-design page. You can simply use setFieldsValue in your first onChange method to set the value of second select field.
handleOperationChange = () => {
this.props.form.setFieldsValue({
Metric: undefined
})
}
I have created a sandbox demo.
In antd, In Class Component, Using Ref, Clear or reset select list value or form item value
add formRef = React.createRef(); just below class component, like:
export default class TestClass extends Component { formRef = React.createRef(); }
add ref={this.formRef} in <Form /> component like this <Form ref={this.formRef}/>
add this line on btn click or in any function you want
this.formRef.current.setFieldsValue({ network: undefined });
Here network in above step is the name of form item
<Form.Item name="network" label="Network"></Form.Item>
Inside handleOperationChange method use resetfileds, this gonna reset your second select box.
this.props.form.resetFields('Metric');
<Select
className="mt-3"
style={{ width: "100%" }}
placeholder="Select your Sub Category"
onChange={handleChangeSubCategory}
disabled={categoryGroup.category === null}
value={categoryGroup.subcategory || undefined}
>
{subCategory.map(item => (
<Option key={item} value={item} label={item}>
<div>
<Avatar style={{ background: "#10899e" }}>
{item[0]}
</Avatar>{" "}
{item}
</div>
</Option>
))}
</Select>
If functional component is used, then we can use Form:
const [form] = Form.useForm()
and it is possible to clear value like this:
const someMethodToClearCurrentSelection = () => {
// ... the code is omitted for the brevity
form.setFieldsValue({ fooProduct: undefined })
}
and our control looks like this:
<Form form={form} name="basic" onFinish={onFinish} layout="vertical">
<Form.Item
key="fooProduct"
name="fooProduct"
label="Some product"
className={s.fooContainer}
rules={[
{
required: true,
message: `Field 'Some produc' is required`,
},
]}
>
<Select
showSearch
optionFilterProp="children"
filterOption={(input, option) =>
option?.children.toLowerCase().includes(input.toLowerCase())
}
allowClear
onChange={handleMarkClick}
>
{products.map((option) => (
<Option key={option.id} value={option.id}>
{option.name}
</Option>
))}
</Select>
</Form.Item>
Read more in antd docs here and examples while migrating from v3 to v4
You can make use of the useEffect() hook.
Define a useForm() custom hook fir your form.
Example: const [form] = Form.useForm();`
Wrap your 1st and 2nd select boxes inside the form and use <Form.Item> to define the input on the form. And whenever the first select's input is changed, clear the 2nd select values in useEffect() hook.
Example:
useEffect(() => {
form.setFieldsValue({
marketplace: [] //2nd select name
});
}, [selectedRegion]); //first select's value
This work perfect for me.

Categories

Resources