In my form, there are 2 children per row in a list: Input and Select
In my input, if I type a set of a string that, when passed into regex, returns either a phone number, url or email, I want the Select component to automatically pre-select this field.
I am watching the Input's getFieldValue
for what type
I should select from the Select component.
The problem I am seeing is that initialValue
for Select is only set on render (kinda makes sense based on it's name). I can't however change it afterwards and I don't know how I can programmatically call Select's onChange
handler from the Input's getFieldValue
.
Is this possible?
import React from "react";
import "./index.css";
import { MinusCircleOutlined, PlusOutlined } from "@ant-design/icons";
import { Button, Form, Input, Select, Space } from "antd";
const { Option } = Select;
const options = [
{ label: "Work", value: "work" },
{ label: "Home", value: "home" },
{ label: "Mobile", value: "mobile" },
{ label: "URL", value: "url" },
{ label: "Email", value: "email" }
];
const validateCurrentInputValueType = (value: string) => {
const isOnlyDigitsRegex = /^\d+$/;
const isURLRegex = /^(?:https?:\/\/)?(?:www\.)?[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+[^\s]*$/;
const isEmailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (isOnlyDigitsRegex.test(value)) return "mobile";
if (isURLRegex.test(value)) return "url";
if (isEmailRegex.test(value)) return "email";
// return "mobile";
};
const App: React.FC = () => {
const [form] = Form.useForm();
const onFinish = (values: any) => {
console.log("Received values of form:", values);
};
const handleChange = () => {
const vals = form.getFieldsValue();
console.log("vals", vals);
};
return (
<Form form={form} name="info-form" onFinish={onFinish} autoComplete="off">
<Form.List name="info">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, fieldKey, ...restField }) => (
<Space key={key} align="baseline">
<Form.Item
label="Details"
{...restField}
name={[name, "info_input"]}
fieldKey={[fieldKey, "info_input"]}
>
<Input />
</Form.Item>
<Form.Item shouldUpdate style={{ marginLeft: 8, width: 100 }}>
{({ getFieldValue }) => {
const currentInputValue = getFieldValue([
"info",
name,
"info_input"
]);
console.log("currentInputValue", currentInputValue);
const type = validateCurrentInputValueType(
currentInputValue
);
console.log("type", type);
return (
<Form.Item
name={[name, "info_select"]}
fieldKey={[fieldKey, "info_select"]}
>
<Select onChange={handleChange}>
{options.map((option) => (
<Option key={option.value} value={option.value}>
{option.label}
</Option>
))}
</Select>
</Form.Item>
);
}}
</Form.Item>
<MinusCircleOutlined onClick={() => remove(name)} />
</Space>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => add()}
block
icon={<PlusOutlined />}
>
Add field
</Button>
</Form.Item>
</>
)}
</Form.List>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
};
export default App;
You can validate the value in input onChange
function and then set the value of select component. If validateCurrentInputValueType
function does not return any value, it'll not set any value for select field.
Here's the complete code.
import React from "react";
import "./index.css";
import { MinusCircleOutlined, PlusOutlined } from "@ant-design/icons";
import { Button, Form, Input, Select, Space } from "antd";
const options = [
{ label: "Work", value: "work" },
{ label: "Home", value: "home" },
{ label: "Mobile", value: "mobile" },
{ label: "URL", value: "url" },
{ label: "Email", value: "email" }
];
const validateCurrentInputValueType = (value: string) => {
const isOnlyDigitsRegex = /^\d+$/;
const isURLRegex = /^(?:https?:\/\/)?(?:www\.)?[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+[^\s]*$/;
const isEmailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (isOnlyDigitsRegex.test(value)) return "mobile";
if (isURLRegex.test(value)) return "url";
if (isEmailRegex.test(value)) return "email";
// return "mobile";
};
const App: React.FC = () => {
const [form] = Form.useForm();
const onFinish = (values: any) => {
console.log("Received values of form:", values);
};
return (
<Form
form={form}
name="infoForm"
onFinish={onFinish}
autoComplete="off"
onValuesChange={(changedValues, values) => {
console.log(changedValues, values);
}}
>
<Form.List name="info">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, ...restField }) => (
<Space key={key} align="baseline">
<Form.Item
label="Details"
{...restField}
name={[name, "info_input"]}
>
<Input
onChange={(e) => {
const type = validateCurrentInputValueType(
e.target.value
);
if (type) {
form.setFieldValue(["info", name, "info_select"], type);
}
}}
/>
</Form.Item>
<Form.Item name={[name, "info_select"]}>
<Select options={options} placeholder="Select Value" />
</Form.Item>
<MinusCircleOutlined onClick={() => remove(name)} />
</Space>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => add()}
block
icon={<PlusOutlined />}
>
Add field
</Button>
</Form.Item>
</>
)}
</Form.List>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
);
};
export default App;