DatePicker : Can't set value manually in componentDidMount event

1 Answer 1105 Views
Calendar DateInput DatePicker DateTimePicker
Cyril
Top achievements
Rank 1
Iron
Cyril asked on 17 Jul 2021, 08:22 PM

Hello, 

I've an issue with DatePicker Component. I created a custom component based on DatePicker.

It's just a component with a fixed label (top, left, right or bottom) with sizing to create form more quickly

After lot of hours of search, no success, I'm forced to post a message on forum to resolve this issue. It's very strangely for me nay impossible without a fix. It's my opinion. 

See below or file in attachment for test and fixing of this issue

Thank you

Cyril REILER

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { withTranslation } from 'react-i18next';
import Proptypes from 'prop-types';
import { DatePicker } from "@progress/kendo-react-dateinputs";
//import { CustomWeekCell } from '../ExtendedClasses';
import moment from 'moment-timezone';

class MyDatePicker extends Component {
    static propTypes = {
        //required
        t: Proptypes.func.isRequired,
        name: Proptypes.string.isRequired,
        callback: Proptypes.func.isRequired,
        style: Proptypes.objectOf(Proptypes.string),
        //optional
        defaultValue: Proptypes.oneOfType([Proptypes.string, Proptypes.number]),
        disabled: Proptypes.bool,
        readOnly: Proptypes.bool,
        required: Proptypes.bool,
        width: Proptypes.number,
        tabIndex: Proptypes.number,
        //Extended by Telerik Component
        labelWidth: Proptypes.oneOfType([Proptypes.string, Proptypes.number]),
        labelHeight: Proptypes.oneOfType([Proptypes.string, Proptypes.number]),
        floatingLabel: Proptypes.string,
        fixedLabel: Proptypes.string,
        labelPosition: Proptypes.string,
        formatPlaceholder: Proptypes.objectOf(Proptypes.string),
        weekNumber: Proptypes.bool,
        format: Proptypes.string,
        value: Proptypes.string,
    }

    static defaultProps = {
        _datepicker: null,
        style: {},
        defaultValue: '',
        disabled: false,
        readOnly: false,
        required: false,
        width: 100,
        tabIndex: -1,
        //Extended by Telerik Component
        labelWidth: "auto",
        labelHeight: "auto",
        floatingLabel: '',
        fixedLabel: '',
        labelPosition: 'left',
        formatPlaceholder: { year: "    ", month: "  ", day: "  " },
        weekNumber: false,
        format: "dd/MM/yyyy",
        value: "",
    }

    /**
     * @constructor
     * @param {Object} props - props of the component
     * @description instantiate component and his state
     */
    constructor(props) {
        super(props);
        this.state = {
            value: props.defaultValue,
        };
    }

    /**
     * 
     */
    componentDidMount() {
        console.log("componentDidMount")
        const {
            value,
            defaultValue,
            format,
        } = this.props;

        console.log(this.props)
        this.setState({
            defaultValue: null,
        });
        this.setState({
            defaultValue: defaultValue,//no effect !!!
            value: value,//no effect !!!
        });
        console.log("value from props");
        console.log(value);

        console.log("value from state");
        console.log(this.state.value);

        console.log("defaultValue from props");
        console.log(defaultValue);

        console.log("defaultValue from state");
        console.log(this.sdefaultValue);

        var root = ReactDOM.findDOMNode(this._root);
        var input = root.querySelector('input');

        console.log("input from DOM");
        console.log(input);

        console.log("input value from DOM");
        console.log(input.value);

        if (input && defaultValue) {
            console.log("force setting manually")
            var s1 = moment(defaultValue, format).format("X");
            input.value = value;//no effect !!!
            input.ariaValuetext = "01/01/2021";//no effect !!!
            input.ariaValuenow = s1 + "000";//no effect !!!
            console.log("check after forcing")
            console.log(input) //no effect !!!
        }
    }

    /**
     * @param {Object} prevProps - the previous props of component
     * @description setDefaultValue if props changed
     */
    componentDidUpdate(prevProps) {
        console.log("componentDidUpdate")
        const {
            value,
            defaultValue,
        } = this.props;

        if (prevProps !== this.props) {
            this.setState({
                defaultValue: defaultValue,
                value: value,
            });
        }
    }

    /**
     * valudeChanged
     * @method
     * @param {Object} e - the event fired
     * @description fired when a value changed - check validators -
     * set the state of component - call callback to notify changed
     */
    onChange = (e) => {
        const {
            //callback,
            //name,
            readOnly,
        } = this.props;
        const value = e.value;
        if (readOnly) {
            return;
        }
        this.setState({
            value,
        });
        //callback({ name: name, value: value }, this, null);
    }

    /**
     * render
     * @description templates the component
     */
    render() {
        const {
            defaultValue,
            value,
        } = this.state;
        const {
            name,
            width,
            disabled,
            style,
            tabIndex,
            readOnly,
            //Extended by Telerik Component
            floatingLabel,
            fixedLabel,
            labelWidth,
            labelHeight,
            labelPosition,
            formatPlaceholder,
            weekNumber,
            format,
        } = this.props;
        const showFixedLabel = fixedLabel && labelPosition && !floatingLabel && (labelWidth || labelHeight);
        let display = "";
        let templateColumns = "";
        let templateRows = "";
        let w = labelWidth ? labelWidth : "auto";
        let h = labelHeight ? labelHeight : "auto";
        if (showFixedLabel) {
            display = "grid";
            switch (labelPosition) {
                case "top": templateRows = h + "px auto"; break;
                case "right": templateColumns = "auto" + w + "px"; break;
                case "bottom": templateRows = "auto" + h + "px"; break;
                case "left": templateColumns = w + "px auto"; break;
                default:
                    return;
            }
        }
        return (
            <div className="k-MyDatePicker-Container k-Theme-Palette-Primary"
                ref={(c) => this._root = c}
                style={{ ...style, display: `${display}`, width: `${w + 2}px`, height: `${h + 2}px`, gridTemplateColumns: `${templateColumns}`, gridTemplateRows: `${templateRows}` }}>
                {showFixedLabel &&
                    (<div className="k-MyDatePicker-Label" style={{ ...style, width: `${w}px`, height: `${h}px` }}>
                        {fixedLabel}
                    </div>)}
                <DatePicker style={{ ...style, width: `${width}px` }}
                    ref={(c) => this._datepicker = c}
                    defaultValue={defaultValue instanceof Date ? defaultValue : null}
                    className="k-MyDatePicker-DatePicker k-Theme-Palette-Secondary"
                    width={width}
                    formatPlaceholder={formatPlaceholder}
                    tabIndex={tabIndex}
                    label={floatingLabel}
                    name={name}
                    weekNumber={weekNumber}
                    disabled={disabled}
                    readonly={readOnly}
                    //weekCell={CustomWeekCell}
                    format={format}
                    onChange={this.onChange} />
            </div>
        )
    }
}

export { MyDatePicker };
const o = withTranslation()(MyDatePicker);
o.displayName = 'MyDatePicker';
export default o;


 

Cyril
Top achievements
Rank 1
Iron
commented on 17 Jul 2021, 09:03 PM

Part of my package.json :

"@progress/kendo-data-query": "^1.5.5",
"@progress/kendo-drawing": "^1.10.1",
"@progress/kendo-licensing": "^1.1.4",
"@progress/kendo-react-animation": "^4.7.0",
"@progress/kendo-react-data-tools": "^4.7.0",
"@progress/kendo-react-dateinputs": "^4.7.0",
"@progress/kendo-react-dropdowns": "^4.7.0",
"@progress/kendo-react-grid": "^4.7.0",
"@progress/kendo-react-inputs": "^4.7.0",
"@progress/kendo-react-intl": "^4.7.0",
"@progress/kendo-react-layout": "^4.7.0",
"@types/react-transition-group": "^4.4.1",

1 Answer, 1 is accepted

Sort by
0
Stefan
Telerik team
answered on 19 Jul 2021, 05:39 AM

Hello, Cyril,

In order to update the value, the component has to be in a controlled mode. This requires setting using the value and onChange props:

https://www.telerik.com/kendo-react-ui/components/dateinputs/datepicker/controlled-state/#toc-controlling-the-date-value

The defaultValue is to only initially set the value and does not allow updating it programmatically later.

More details about using controlled and uncontrolled components can be seen here:

https://goshakkk.name/controlled-vs-uncontrolled-inputs-react/

Regards,
Stefan
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Cyril
Top achievements
Rank 1
Iron
commented on 19 Jul 2021, 07:02 AM | edited

Hello Stefan,

Thank you for this feedback.

Why this component can't be update. It's logic and important to initialize a component in a form ?

I will create my own DatePicker based on Input and Calendar Component to resolve this issue now.

It's not a problem but it's just a question of additional time in our developpment.

Best regards
Stefan
Telerik team
commented on 19 Jul 2021, 07:20 AM | edited

If you share a runnable example with the issue I will be happy to take a look at it and assist in resolving it.

The component can be updated by default.

Also, if it is used in a Form, the Form will automatically update it, there is no need to set the value to it.

If the Form has default values, then the initial values of the Form has to be set. If we need to update the Form initial value after a request, this approach can be used:

https://www.telerik.com/kendo-react-ui/components/form/advanced-scenarios/#toc-resetting-the-form-initial-state

This will automatically update the DatePicker value as well.

Cyril
Top achievements
Rank 1
Iron
commented on 19 Jul 2021, 11:24 AM

Hello Stefan,

This issue is based on the form unmounting into a panel (PanelBar or OtherPanel too)

After expanding (mounting), all values aren't initialized in form.

With this components : Input, MaskedTextBox, NumericTextBox, TextArea, I can initialize manually

With this components : All date Inputs components, I can't initialize manually

Si screenshot below :

Best regards

Cyril

Stefan
Telerik team
commented on 19 Jul 2021, 11:47 AM

Hello, Cyril,

The KendoReact DateInputs are working the same way as the other editors in the Form.

In my previous reply, I sent an example that shows how to load the values on a later state. I updated it to use the DatePicker and it was working as expected:
https://stackblitz.com/edit/react-mjv4x6?file=app/main.jsx

If there is an issue in the real application, please share a runnable example reproducing it. This is a supported functionality and should be working as expected.

Tags
Calendar DateInput DatePicker DateTimePicker
Asked by
Cyril
Top achievements
Rank 1
Iron
Answers by
Stefan
Telerik team
Share this question
or