marmelab / react-admin

A frontend Framework for single-page applications on top of REST/GraphQL APIs, using TypeScript, React and Material Design
http://marmelab.com/react-admin
MIT License
24.99k stars 5.25k forks source link

DateInput parse and format does not display the value in the input #6315

Closed jasonlimantoro closed 2 years ago

jasonlimantoro commented 3 years ago

What you were expecting:

When entered manually:

When entered via the browser's datepicker:

What happened instead:

When entered manually:

https://user-images.githubusercontent.com/31163334/120006297-59e0a580-c00b-11eb-9823-152e52bea6c5.mov

Here, I tried to enter 02 03 2021 directly from the input field.

When entered via the browser's datepicker:

https://user-images.githubusercontent.com/31163334/120007694-c3ad7f00-c00c-11eb-9ee5-421feddd4b26.mov

Steps to reproduce:

  1. Use the example from the docs in the Transforming Input value to and from record section :).
  2. Enter any date manually, for example, type 02 03 2021. See that the input does not reflect what you type.
  3. Or, select the date picker, select any date, and then click anything to remove the focus. See that the input becomes mm/dd/yy literally.

Related code:

<DateInput
    label="Start from"
    source="startFrom"
    defaultValue={new Date()}
    format={dateFormatter}
    parse={dateParser}
/>

where dateParser and dateFormatter is the following (straight copy-paste from the docs):

const dateFormatter = (v) => {
    // v is a `Date` object
    if (!(v instanceof Date) || Number.isNaN(v)) return;
    const pad = "00";
    const yy = v.getFullYear().toString();
    const mm = (v.getMonth() + 1).toString();
    const dd = v.getDate().toString();
    return `${yy}-${(pad + mm).slice(-2)}-${(pad + dd).slice(-2)}`;
};

const dateParser = (v) => {
    // v is a string of "YYYY-MM-DD" format
    const match = /(\d{4})-(\d{2})-(\d{2})/.exec(v);
    if (match === null) return;
    const d = new Date(
        match[1],
        parseInt(match[2], 10) - 1,
            match[3]
    );
    if (Number.isNaN(d)) return;
    return d;
};

Other information:

Looks like a regression in the version 3.15.2. Visual bug because the form validation (required()) works just fine.

Environment

danaralifian commented 3 years ago

you should avoid onBlur, this work for me <DateInput label="Start from" source="startFrom" defaultValue={new Date()} format={dateFormatter} parse={dateParser} options={{onBlur : ()=>{}}} />

djhi commented 3 years ago

Thanks for reporting this. I can't reproduce it on our simple example. Please provide a sample application showing the issue by forking the following CodeSandbox (https://codesandbox.io/s/github/marmelab/react-admin/tree/master/examples/simple).

fzaninotto commented 3 years ago

No news for some time, closing.

mikemcclaran commented 2 years ago

Here is example of the issue being reproduced https://codesandbox.io/s/eloquent-fog-4bbml?file=/src/posts/PostCreate.tsx

I added the parser and formatter functions from the docs to the published_at DateInput in PostCreate.tsx. The DateInput no longer shows the date that you have selected.

WiXSL commented 2 years ago

The original code in the example was updated and fix over time, but the documentation wasn't changed.

cwagner22 commented 2 years ago

This issue is still happening, as you can see here: https://codesandbox.io/s/festive-newton-fxg5f8?file=/src/posts/PostCreate.tsx When creating a post, Published At doesn't show the custom format:

image
slax57 commented 2 years ago

@cwagner22 There are two things wrong with the parse function in your codesandbox:

  1. you should return the current value if it fails to parse it

    - if (match === null) return;
    + if (match === null) return value;

    and

    - if (isNaN(d.getDate())) return;
    + if (isNaN(d.getDate())) return value;
  2. your regex should not be valid for incomplete dates, such as 0002-10-24 (when I'm typing 24/10/2...) Here is a quick workaround

    - const dateParseRegex = /(\d{4})-(\d{2})-(\d{2})/;
    + const dateParseRegex = /([1-2]\d{3})-(\d{2})-(\d{2})/;

Remember that the parse function gets called at each character you type in the input. If you want to transform the value only at form submission, you should rather use the transform prop available on <Create> or <Edit>. (see https://marmelab.com/react-admin/Create.html#transform)

cwagner22 commented 2 years ago

@slax57 Thank you for looking into it. However I've added your changes and it's still not working. When I type a date in the Published At input, I can see in the console logs it parses and returns a correct formatted value, but the value displayed in the input stays in the old format. Still the same link: https://codesandbox.io/s/festive-newton-fxg5f8?file=/src/posts/PostCreate.tsx

slax57 commented 2 years ago

@cwagner22 if your issue is about the display format of the date in the browser, then there is nothing we can do about it. Actually DateInput renders a simple <input type="date"> and then the browser takes over.

From the MDN docs:

The displayed date format will differ from the actual value — the displayed date is formatted based on the locale of the user's browser, but the parsed value is always formatted yyyy-mm-dd.