skip to Main Content

I’m working on a React form using Ant Design’s Form component. The form includes several dropdowns, including facility, specialization, and doctor. The doctor dropdown should be cleared whenever the facility or specialization dropdown values change, and the doctor dropdown should be repopulated based on the new facility and specialization values.

Here’s a summary of the setup:

  • I’m using Ant Design’s Form component and useForm hook to manage the
    form state.
  • The doctor dropdown is a custom component called SearchableDropDown
    that fetches options based on the selected facility and
    specialization.
  • I want the doctor dropdown to clear its value whenever the facility
    or specialization changes.

Issue:
Despite calling form.setFieldsValue({ doctorId: undefined }); and setting setDoctor(null); in the useEffect hook, the doctorId dropdown does not clear its value as expected when facility or specialization changes.

Code Example:
you can find the code here on Stack Blitz

What I’ve Tried:

  1. Setting the doctorId field value to undefined or null.
  2. Adding a key prop to the SearchableDropDown to force
    re-rendering.
  3. Manually setting the doctor state to null.

Question:
How can I programmatically clear the doctorId dropdown value when either the facility or specialization dropdown changes in an Ant Design form? What is the correct approach to ensure that the doctor dropdown is cleared and reset based on the new facility and specialization selections?

Any advice or suggestions would be greatly appreciated. Thanks in advance!

enter image description here

2

Answers


  1. Add an internal state internalValue inside your SearchableDropDown to track the passed value.

        const [internalValue, setInternalValue] = useState(value);
    

    Pass it to the Select as value

        <Select
          value={internalValue}
          ...
        />
    

    And the value can be set to undefined in case the change of the queryParams

      useEffect(() => {
        setInternalValue(undefined);
      }, [queryParams]);
    
    Login or Signup to reply.
  2. doctorId field is not reset is because you didn’t connect form with Form component. Second there’s no need to store facilityId, specializationId or any form field related field in state since you can get watch from form.getFieldValue or Form.useWatch(‘facilityId’) if you watch the value of a field. You can use onChange on facilityId and specializationId to reset doctorId value form.resetFields(['doctorId])

    Here’s the complete code with some improvements

    page.tsx

    "use client";
    
    import { Form, DatePicker, Button, Col, Row } from "antd";
    import SearchableDropDown from "@/componets/SearchableDropDown";
    import { DDL_Type } from "@/interfaces/common";
    import { useCallback, useMemo } from "react";
    
    type FormValuesType = {
        facilityId: string;
        specializationId: string;
        doctorId: string;
        dateTime: string;
    };
    
    export default function Home() {
        const [form] = Form.useForm<FormValuesType>();
        const onFinish = (values: FormValuesType) => {
            console.log("Received values of form: ", values);
        };
    
        const getDoctorFieldParams = useCallback(() => {
            const params = new URLSearchParams();
            const facility = form.getFieldValue("facilityId");
            const specialization = form.getFieldValue("specializationId");
    
            if (facility) params.append("facilityId", facility);
            if (specialization) params.append("specializationId", specialization);
    
            return params.toString();
        }, [form]);
    
        const resetDoctorIdDropdown = () => form.resetFields(["doctorId"]);
    
        return (
            <div className="container mx-auto p-4">
                <Form<FormValuesType>
                    form={form}
                    layout="vertical"
                    onFinish={onFinish}
                    className="bg-white p-6 rounded-lg shadow-md"
                >
                    <h2 className="text-xl mb-4">Appointment Details</h2>
                    <Row gutter={16}>
                        <Col span={12}>
                            <Form.Item<FormValuesType>
                                name="facilityId"
                                label="Facility"
                                rules={[{ required: true, message: "Please select a facility" }]}
                            >
                                <SearchableDropDown
                                    allowClear={true}
                                    onChange={resetDoctorIdDropdown}
                                    showSearch
                                    style={{ width: "100%" }}
                                    placeholder="Search by facility"
                                    ddl_type={DDL_Type.Facility}
                                    className="flex-1"
                                />
                            </Form.Item>
                        </Col>
                        <Col span={12}>
                            <Form.Item<FormValuesType>
                                name="specializationId"
                                label="Specialization"
                                rules={[
                                    { required: true, message: "Please select a specialization" },
                                ]}
                            >
                                <SearchableDropDown
                                    onChange={resetDoctorIdDropdown}
                                    allowClear={true}
                                    showSearch
                                    style={{ width: "100%" }}
                                    placeholder="Search by doctor"
                                    ddl_type={DDL_Type.Specialization}
                                    className="flex-1"
                                />
                            </Form.Item>
                        </Col>
                    </Row>
                    <Row gutter={16}>
                        <Col span={12}>
                            <Form.Item<FormValuesType>
                                name="doctorId"
                                label="Doctor"
                                rules={[{ required: true, message: "Please select a doctor" }]}
                            >
                                <SearchableDropDown
                                    allowClear={true}
                                    getQueryParams={getDoctorFieldParams}
                                    showSearch
                                    style={{ width: "100%" }}
                                    placeholder="Search by doctor"
                                    ddl_type={DDL_Type.Doctor}
                                    className="flex-1"
                                />
                            </Form.Item>
                        </Col>
                        <Col span={12}>
                            <Form.Item<FormValuesType>
                                name="dateTime"
                                label="Appointment Date & Time"
                                rules={[
                                    { required: true, message: "Please select a date and time" },
                                ]}
                            >
                                <DatePicker
                                    showTime
                                    minuteStep={15}
                                    needConfirm={false}
                                    use12Hours={true}
                                    format="YYYY-MM-DD HH:mm"
                                    className="w-full"
                                    placeholder="Select Date & Time"
                                />
                            </Form.Item>
                        </Col>
                    </Row>
    
                    <Form.Item>
                        <Button type="default" htmlType="submit" className="w-full">
                            Book Appointment
                        </Button>
                    </Form.Item>
                </Form>
            </div>
        );
    }
    

    SearchableDropDown.tsx

    "use client";
    import React, { useEffect, useMemo, useRef, useState } from "react";
    import debounce from "lodash/debounce";
    import { Form, Select, Spin } from "antd";
    import type { SelectProps } from "antd/es/select";
    import { DDL_Type, fetch_ddl } from "@/interfaces/common";
    
    interface SearchableDropDownProps
        extends Omit<SelectProps<string>, "options" | "children"> {
        debounceTimeout?: number;
        getQueryParams?: () => string;
        onChange?: (value: string) => void;
        ddl_type: DDL_Type;
    }
    
    function SearchableDropDown(props: SearchableDropDownProps) {
        const { ddl_type, getQueryParams, debounceTimeout = 800, ...rest } = props;
    
        const fetchRef = useRef(0);
        const [fetching, setFetching] = useState(false);
        const [options, setOptions] = useState<{ label: string; value: string }[]>(
            [],
        );
    
        const debounceFetcher = useMemo(() => {
            const loadData = async (value: string) => {
                fetchRef.current += 1;
                const fetchId = fetchRef.current;
                setOptions([]);
                setFetching(true);
                try {
                    const queryParams = getQueryParams ? getQueryParams() : "";
                    const newOptions = await fetch_ddl(value, ddl_type, queryParams);
                    if (fetchId === fetchRef.current) {
                        setOptions(newOptions);
                        setFetching(false);
                    }
                } catch (error) {
                    console.error("Error fetching data:", error);
                    setFetching(false);
                }
            };
    
            return debounce(loadData, debounceTimeout);
        }, [ddl_type, getQueryParams, debounceTimeout]);
    
        useEffect(() => {
            debounceFetcher("");
        }, [debounceFetcher]);
    
        return (
            <Select
                filterOption={false}
                onSearch={debounceFetcher}
                loading={fetching}
                notFoundContent={fetching ? <Spin size="small" /> : null}
                {...rest}
                options={options}
            />
        );
    }
    
    export default SearchableDropDown;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search