Search code examples
javascriptreactjsreact-datetime

How to prevent the calendar from opening when react-datetime input is readOnly


I'm using react-datetime module in my form along with formik.

import React, { useImperativeHandle, useReducer, forwardRef } from 'react';
import PropTypes from 'prop-types';
import { Form} from "react-bootstrap";

import "react-datetime/css/react-datetime.css";

import { useFormik} from 'formik';
import * as yup from "yup";
import Datetime from 'react-datetime';
import moment from 'moment';
import { reducer } from '../common/reducer'


// Restrict future dates when entering "Date of Birth"
const validDOB = function( current ){
    return current.isBefore(moment());
};

// Initial states of WorkloadForm
const initialState = {
    doesExist: false
};

const WorkloadForm = forwardRef((props, ref) => {
    // State Handling
    const [state, dispatch] = useReducer(reducer, initialState);

    
    // Initial Values for the WorkfloadForm
    const initialValues = {
        patDOB: '',
    }

    // Validation schema for form fields
    const validationSchema = yup.object().shape({
        patDOB: yup.string()
                        .test('invalid-dob', 'Please enter a valid DOB.', value => {
                            const dob = moment(value, 'DD-MM-YYYY', true);
                            return dob.isValid();
                        }),
    });

    // Form Submission Action
    const handleSubmit = (values, actions) =>{
        
    }

    // Formik initialization of 'useFormik'
    const formik = useFormik({
        initialValues: initialValues,
        onSubmit: handleSubmit,
        validationSchema: validationSchema
    });

    // 'useImperativeHandle' to call formik actions from parent component
    useImperativeHandle(ref, () => ({
        ...formik
    }), []);

    return (
        <>
            <Form noValidate onSubmit={formik.handleSubmit}>
                <Form.Group controlId="patDOB">
                    <Form.Label>Date of Birth</Form.Label>
                    <Datetime
                        inputProps={{
                            placeholder: 'DD-MM-YYYY',
                            id: 'patDOB',
                            name: 'patDOB',
                            readOnly: state.doesExist ? true: false,
                            className: formik.errors.patDOB && formik.touched.patDOB ? "form-control is-invalid": "form-control"
                        }}
                        closeOnSelect={true}
                        dateFormat="DD-MM-YYYY"
                        timeFormat={false}
                        value={formik.values.patDOB}
                        isValidDate={validDOB}
                        onChange={(dateFromValue) => {
                            formik.setFieldValue('patDOB', moment(dateFromValue).format('DD-MM-YYYY'));
                            }
                        }
                        renderInput={(props) => {
                            return <input {...props} value={(formik.values.patDOB) ? props.value : ''} />
                        }}
                    />
                    {formik.errors.patDOB && formik.touched.patDOB ? (
                            <div className="text-danger" style={{fontSize: '0.875em'}}>{formik.errors.patDOB}</div>
                    ) : null}
                </Form.Group>
            </Form>
        </>
    );
})

WorkloadForm.propTypes = {
    api: PropTypes.object.isRequired
};

export default WorkloadForm;

readOnly prop is working fine and it's conditional.

My issue is that I can still open the calendar or picker when I touch the field even though its readOnly.

Issue

How to prevent the field from opening the picker/calendar when it's readOnly?

Thanks


Solution

  • You can pass the open prop to false

    <Datetime open={false} />
    

    or in your case if the condition is the state.doesExist you could use the state value

    <Datetime open={!state.doesExist} />
    

    Or if you want to keep the default behavior if your state is true maybe you could try

    <Datetime open={state.doesExist ? false : null} />
    

    Edit:

    For some reason, explicitely setting the null default value of the open prop, doesn't work, I found that workaround which is quite ugly but works...

    <Datetime 
    //...props
    {...Object.assign({}, state.doesExist ? {open:false} : {})}
     />