Search code examples
reactjsantd

Antd input value property undefined


I have Antd dropdown component with input field. when i press + and - buttons it populate the values in the input field, but when i click on submit i get value of undefined. i Have tried to nest Form.Item one level below but it is undefined again.

my component looks like this

dropdown

const PeopleNumber = () => {
    const [adult, setAdult] = useState(0);
    const [child, setChild] = useState(0);
    const [passcount, setPasscount] = useState('Adult (0), Child(0)');

    const menu = () => {
        return (
            <>
                <div className="adult-child-drawer">

                    <div className="adult-child-button">
                        Adult
                        <span style={{float: 'right'}}>
                         <PlusCircleOutlined onClick={addAdult} style={{margin: '8px'}}/>
                            {adult}
                            <MinusCircleOutlined onClick={removeAdult} style={{margin: '8px'}}/>
                        </span>
                    </div>
                    <div className="adult-child-button">
                        Child
                        <span style={{float: 'right'}}>
                        <PlusCircleOutlined onClick={addChild} style={{margin: '8px'}}/>
                            {child}
                            <MinusCircleOutlined onClick={removeChild} style={{margin: '8px'}}/>
                        </span>
                    </div>
                </div>

            </>

        );
    };

    useEffect(() => {
        setPasscount(`Adult (${adult}), Child(${child})`);
    }, [adult, child]);

    const addAdult = () => {
        setAdult((prevAdult) => prevAdult + 1);
    };

    const removeAdult = () => {
        if (adult > 0) setAdult((prevAdult) => prevAdult - 1);
    };

    const addChild = () => {
        setChild((prevChild) => prevChild + 1);
    };

    const removeChild = () => {
        if (child > 0) setChild((prevChild) => prevChild - 1);
    };

    return (
        <>
            <div className="people-form">
                <Form.Item name='people'>
                    <Dropdown overlay={menu} trigger={['click']}>
                        <Input value={(adult || child > 0)?passcount:''}  placeholder={passcount} style={ (adult || child !== 0)?{color:'#5A5B5B'}: {color:'#B3B4B5'}} bordered={false}/>
                    </Dropdown>
                </Form.Item>
            </div>
        </>
    );
};

export default PeopleNumber;

PeopleNumber component is added to the parent component which submits. After submit i get values of all other components except PeopleNumber.Please help.

const onFinish = (value) => {
        console.log('values are:', value)
    }
 <Form onFinish={onFinish} form={form}>

      <From/>
      <To/>
      <Date/>               
      <PeopleNumber/>
      <Button htmlType='submit
           Search
      </Button>
<Form/>

Solution

  • Complete Code Changes: Set the people value in useEffect using form Need To Pass form from Parent Component to People Number Component

    import { useEffect, useState } from 'react';
    import { Button, Dropdown, Form, Input } from 'antd';
    import { MinusCircleOutlined, PlusCircleOutlined } from '@ant-design/icons';
    
    const PeopleNumber = (props) => {
        const { form } = props;
        const [adult, setAdult] = useState(0);
        const [child, setChild] = useState(0);
        const [passcount, setPasscount] = useState('Adult (0), Child(0)');
    
        const menu = () => {
            return (
                <>
                    <div className='adult-child-drawer'>
                        <div className='adult-child-button'>
                            Adult
                            <span style={{ float: 'right' }}>
                                <PlusCircleOutlined onClick={addAdult} style={{ margin: '8px' }} />
                                {adult}
                                <MinusCircleOutlined onClick={removeAdult} style={{ margin: '8px' }} />
                            </span>
                        </div>
                        <div className='adult-child-button'>
                            Child
                            <span style={{ float: 'right' }}>
                                <PlusCircleOutlined onClick={addChild} style={{ margin: '8px' }} />
                                {child}
                                <MinusCircleOutlined onClick={removeChild} style={{ margin: '8px' }} />
                            </span>
                        </div>
                    </div>
                </>
            );
        };
    
        useEffect(() => {
            let value = `Adult (${adult}), Child(${child})`;
            setPasscount(value);
            form.setFieldsValue({ people: value });
        }, [adult, child, form]);
    
        const addAdult = () => {
            setAdult((prevAdult) => prevAdult + 1);
        };
    
        const removeAdult = () => {
            if (adult > 0) setAdult((prevAdult) => prevAdult - 1);
        };
    
        const addChild = () => {
            setChild((prevChild) => prevChild + 1);
        };
    
        const removeChild = () => {
            if (child > 0) setChild((prevChild) => prevChild - 1);
        };
    
        return (
            <>
                <div className='people-form'>
                    <Form.Item name='people'>
                        <Dropdown overlay={menu} trigger={['click']}>
                            <Input
                                value={adult || child > 0 ? passcount : ''}
                                placeholder={passcount}
                                style={adult || child !== 0 ? { color: '#5A5B5B' } : { color: '#B3B4B5' }}
                                bordered={false}
                            />
                        </Dropdown>
                    </Form.Item>
                </div>
            </>
        );
    };
    
    const App = () => {
        const [form] = Form.useForm();
    
        const onFinish = (value) => {
            console.log('values are:', value);
        };
    
        return (
            <Form form={form} onFinish={onFinish}>
                <PeopleNumber form={form} />
                <Button htmlType='submit' type='primary'>
                    Submit
                </Button>
            </Form>
        );
    };
    
    export default App;
    

    Solution: If you want the same value that you show in input as placeholder, you can replace your useEffect with the following code

    useEffect(() => {
        let value = `Adult (${adult}), Child(${child})`;
        setPasscount(value);
        form.setFieldsValue({ people: value });
    }, [adult, child, form]);
    

    TLDR:

    <Form.Item name='people'>
       <Dropdown overlay={menu} trigger={['click']}>
         <Input value={(adult || child > 0)?passcount:''}  placeholder={passcount} style={ (adult || child !== 0)?{color:'#5A5B5B'}: {color:'#B3B4B5'}} bordered={false}/>
       </Dropdown>
    </Form.Item>
    

    If you try to type in Input Field, it will not work as <Form.Item> requires a single & direct field in order to make work. You are getting undefined just because you wrapped Input Field with Dropdown and <Form.Item>.

    But if you wrap <Form.Item> with Dropdown, now you can type in input field.

    Now your question will be if you are setting the value of Input Field, why it doesn't show up after submitting the form even you move dropdown outside the <Form.Item>?

    Answer: Since you are using antd form hook and it controls the Input Field which is wrapped in <Form.Item> automatically. Since you just pass the value but did not set the value using form.setFieldsValue({people: someValue }). That's why it doesn't show up when you submit the form.