Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to select same date in date range picker #1759

Closed
kirill-konshin opened this issue May 8, 2020 · 31 comments · Fixed by mui/material-ui#23701
Closed

Add ability to select same date in date range picker #1759

kirill-konshin opened this issue May 8, 2020 · 31 comments · Fixed by mui/material-ui#23701
Labels

Comments

@kirill-konshin
Copy link

It possible to select same date to make one day range. It currently gives validation error: https://dev.material-ui-pickers.dev/demo/daterangepicker

image
image

Follow up for #364 (comment)

@oliviertassinari
Copy link
Member

For benchmark https://www.google.com/flights and https://www.airbnb.com/ allows selecting the same date while https://www.booking.com/ doesn't.

@btroop
Copy link

btroop commented May 9, 2020

Would be great to add a prop to the api to allow or not allow the same date validation

@dmtrKovalenko
Copy link
Member

dmtrKovalenko commented May 11, 2020

I am wondering about the better API for that. Maybe something like minRangeLength and maxRangeLength? That by default will be 1 and null.

@oliviertassinari
Copy link
Member

oliviertassinari commented May 11, 2020

@dmtrKovalenko A side but related question. Should we move the validation outside of the DateRangePicker, as we did for the DatePicker?

In this approach, developers would have the following workaround: they could flag same-day selection as valid.

@dmtrKovalenko
Copy link
Member

dmtrKovalenko commented May 11, 2020

It already has the same validation as DatePicker with onError. But invalidRange reason returns when the start and end dates are the same

@oliviertassinari
Copy link
Member

oliviertassinari commented May 11, 2020

It already has the same validation as DatePicker with onError

@dmtrKovalenko So people can already add a conditional to their onError handler?
if reason === 'invalidRange' && startDate === endDate then ignore

@dmtrKovalenko
Copy link
Member

dmtrKovalenko commented May 11, 2020

Yes, but it will look like

const [error, setError] = React.useState([null, null])

<DateRange
  onError={([startReason, endReason], [start, end]) => { 
     if (startReason === 'invalidRange' && isSameDay(start, end)) {
       setError([null, null])
       return;
     }

     setError([startReason, endReason])
  })}
  renderInput={props => <TextField {...props} error={Boolean(error[0])} />   }
/>

@oliviertassinari
Copy link
Member

oliviertassinari commented May 11, 2020

@dmtrKovalenko This looks perfect for the "lazy" solution, to let end-users fall into this trap and get visual/text feedback 👌. However, there is another side to the problem.

I assume the concern now is about: Should the UI prevent this case in the first place? It would give faster feedback in the UI, this sounds fair.

Should it be done with a minRangeLength and maxRangeLength props? What if we went with the most flexible API: A callback method that determines if the user can select a range between two dates? This could extend the support to a use case like this: prevent the end of the range to be a weekend.

Related:

@dmtrKovalenko
Copy link
Member

dmtrKovalenko commented May 11, 2020

A callback method that determines if the user can select a range between two dates?

I thought about such api, and prepeared special design for this case – we have a function https://github.com/mui-org/material-ui-pickers/blob/7bed283699ef768936a3ec7c5dc89571492dddd4/lib/src/DateRangePicker/date-range-manager.ts#L12

that calculates range changes, we can expose the prop that will replace function and will make possible to significantly customize range picking behavior

@oliviertassinari
Copy link
Member

oliviertassinari commented May 11, 2020

@dmtrKovalenko Awesome. Maybe we should wait to get more feedback from the developers before making a step further in any direction :D?

@kirill-konshin
Copy link
Author

Determining the kind of error in onError is quite awkward and verbose to me...

Taking into account that this component might be part of something like redux-form so all validation would be external, I'd suggest to just allow same date and let external validation to produce an error. And give an ability to provide this error to datepicker.

@oliviertassinari
Copy link
Member

@kirill-konshin You are free to override the built-in validation. If it's what you are looking for, then you are already covered.

@kirill-konshin
Copy link
Author

@kirill-konshin You are free to override the built-in validation. If it's what you are looking for, then you are already covered.

Will it allow to suppress the same-day error? Can you point on any example how to do it?

@sergiolenza
Copy link

Hi folks.
I'm also having this issue (or wrong behavior to me) and I've seen that the calendar popper does not close when the dates are the same and it should IMHO.

@oliviertassinari
Copy link
Member

@sergiolenza Interesting, thanks for raising. This makes me think of:

Do you have a preference on how the problem should be fixed?

@farchijets

This comment has been minimized.

@kirill-konshin
Copy link
Author

Currently you can only select an end date that is later than the start date. Selecting the end date first and start date second is not possible. It would be useful to have it go both ways.

I had that in mind but upon checking Kayak, Google Flights and some others I noticed they are not allowing this. But I personally agree that it’s useful.

@dmtrKovalenko
Copy link
Member

That’s where I think exposing custom range strategy should help: #1759 (comment)

@sergiolenza
Copy link

@sergiolenza Interesting, thanks for raising. This makes me think of:

Do you have a preference on how the problem should be fixed?

I think the issue begins here, where we get ['invalidRange', 'invalidRange'].

var validationError = useDateRangeValidation(value, restProps);

Inside the useDateRangeValidation function:

var useDateRangeValidation = makeValidationHook(validateDateRange, {
  defaultValidationError: [null, null],
  isSameError: function isSameError(a, b) {
    return a[1] === b[1] && a[0] === b[0];
  }
});

I see the isSameError property is forcing the wrong behavior.

So should we can start solve this issue here?

@sergiolenza

This comment has been minimized.

@oliviertassinari
Copy link
Member

@dmtrKovalenko What do you think about this resolution?

  1. We use the same default behavior as https://www.daterangepicker.com/#examples, hoping that in 5 years of business as a leading solution, they did some good tradeoff. Same behavior as AntD: users can select the same day without any error.
  2. We introduce a new API for implementing custom range, optimizing for flexibility
/**
 * Determine if the current range can be selected by the user.
 * For instance, it can be used to prevent the selected range to end the weekend.
 */
isRangeAvailable?: (range: [ParsableDate, ParsableDate]) => boolean;

While 1. is breaking, 2. could be implemented later on.

@mlasy
Copy link

mlasy commented Jul 13, 2020

Users can select the same day without any error would be sufficient here imho

@bsides
Copy link

bsides commented Dec 31, 2020

Just noting that even though the option allowSameDateSelection is true, it still returns an error, making the popup not close automatically and the fields becoming red (also error has invalidRange on them). I expected this prop to take care of it.

@oliviertassinari
Copy link
Member

@bsides Please try with @material-ui/lab@v5.0.0-alpha.21.

@bsides
Copy link

bsides commented Jan 4, 2021

Unfortunatelly it's hard to test @oliviertassinari because I do use other stuff from the lab and they're not at that version (should be bumped?)

image

@oliviertassinari
Copy link
Member

@bsides Make sure all your dependencies are on v5

@bsides
Copy link

bsides commented Jan 4, 2021

@bsides Make sure all your dependencies are on v5

Oh, I was using @material-ui/pickers, just noticed it merged with lab... so I should just use lab and remove pickers, right? Now a question, what should I fill in place of DateFnsUtils since it doesnt exist anymore in the LocationProvider` component?

It used to be...

image

Thanks again

@oliviertassinari
Copy link
Member

@bsides Please have a look at https://next.material-ui.com/guides/pickers-migration/. If you see anything missing, let us know.

@anthony-brown-5pm
Copy link

Bump, I have completely opposite issue, where by default it allows selecting the same date on both fields, wondering how to disable that, and ensure dates are at least a day apart? I tried in the onChange method to set the second date to null if its teh same, it works when first clicking it but on the second click it ignores it and just sets the same date again.

@LukasTy
Copy link
Member

LukasTy commented Feb 5, 2024

@anthony-brown-5pm Just a friendly reminder that this package is no longer maintained.
Feel free to use @mui/x-date-pickers, the shouldDisableDate validation callback provides a second position parameter, with which you can achieve your desired result. 😉

@cbordon
Copy link

cbordon commented Feb 28, 2024

Hi all, this isn't so much a solution, but rather a work around.

Basically, if only one date is selected a button will pop up below the calendar.
By clicking the button it simply closes the calendar.

Now you will only have one date in your date input.

Without the button visually popping up, it is confusing for the user to know that they are allowed to just exit the calendar without selecting an end date and that is why I added a button that manually closes the calendar.

On your following page when you are reading the form data, just account for the fact that you only have one date and implement the logic as your app requires. e.g if end_date not set, end_date = start_date

In this code snippet, the button logic is just in the onShow and onSelect methods.

const datePicker = new AirDatepicker("#hero-datepicker", {
            locale: $locale,
            isMobile: true,
            range: true,
            multipleDatesSeparator: ' — ',
            autoClose: true,
            minDate: startPickerMin.toISODate(),
            maxDate: startPickerMax.toISODate(),
            onSelect: function(formattedDate, date) {
                const $closeButton = $('<button class="datepicker-close-button">Start and end dates are the same</button>');
                $('.air-datepicker .datepicker-close-button').remove(); // Remove existing close buttons
                if (datePicker.selectedDates.length == 1) {
                    $('.air-datepicker').append($closeButton);
                }
        
                $closeButton.on('click', () => {
                    datePicker.hide();
                });
            },
            onShow: function(formattedDate, date) {
                const $closeButton = $('<button class="datepicker-close-button">Start and end dates are the same</button>');
                $('.air-datepicker .datepicker-close-button').remove(); // Remove existing close buttons
                if (datePicker.selectedDates.length == 1) {
                    $('.air-datepicker').append($closeButton);
                }
        
                $closeButton.on('click', () => {
                    datePicker.hide();
                });
            }
        });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.