user17595824
user17595824

Reputation:

How to disable certain days and dates in MUI react datepicker based on a json array?

I have Laravel app that returns a json response of dates and days of the week that should be disabled in the datepicker

For example this is my datesOff constant when I console.log() it ['2022-05-08', '2022-05-11', '2022-05-19']

And This is daysOff constant when I console.log() it [3, 6]

So how do I disable both returned dates and days(wednesday and sunday in this case)

    useEffect(() => {
      axios.get(bookingUrl).then((response) => {
        setDaysOff(response.data.daysOff);
        setDatesOff(response.data.datesOff);
        setBooked(response.data.booked);
      })
    }, []);

<LocalizationProvider locale={hr} dateAdapter={AdapterDateFns}>
            <DatePicker
            label="Date"
            disablePast={true}
            minDate={minDate}
            maxDate={maxDate}
            value={date}
            shouldDisableDate={//What do i to here
            }
            onChange={(newDate) => {
            setDate(newDate);
            }}
            renderInput={(params) => <TextField {...params} />}

Upvotes: 1

Views: 5332

Answers (3)

Muhammad Jamshaid
Muhammad Jamshaid

Reputation: 21

Appreciate the answer from Dmitriif the code is working fine except one issue with the code is the array of dates not disabling the dates from the array such as date: 2020-05-19 and It's disabled the 2020-05-20 to fix that you need to update the one line of code:

const stringifiedDate = date.toISOString().slice(0, 10);

to:

const stringifiedDate = dayjs(date).format('YYYY-MM-DD');

install dayjs and import in your file. and you are good to go.

thanks again to Dmitriif

Upvotes: 2

user18121438
user18121438

Reputation: 1

My answer is based on the answer by Dmitriif but it has been changed because it caused many renders through the process of selecting a date.

const customDayRenderer = (
    date: Date,
    selectedDates: Array<Date | null>,
    pickersDayProps: PickersDayProps<Date>
) => {
    amountOfExercises.forEach(day => {
        selectedDates.push(new Date(day.exerciseDate))
    });

    return <PickersDay {...pickersDayProps}  sx={{
        [`&&.${pickersDayClasses.selected}`]: {
          backgroundColor: "#EBEBE4",
          cursor: 'not-allowed'
        }
      }} />;
};

<DatePicker
   disablePast={true}
   label="Exercise Date"
   **renderDay={customDayRenderer}**
   value={dateValue}
   onChange={(newDateValue) => {
     setNewDateValue(newDateValue);
   }}
   renderInput={(params) => <TextField {...params} />}
/>

The amountOfExercises is a JSON array and inside the forEach. I'm extracting the date I want to disable and push it to the selectedDates array.

After doing this you will notice that the background color of the dates you want disable had changed meaning the DatePicker "knows" what dates are supposed to be selected.

In order to give the user a feeling that the selectedDates are not available for the (disabled) selection I've added the sx attribute which gives a lightgray background color and a cursor which is not allowed.

The date variable inside customDayRender in my code is never read but when trying to delete it I've got an error that the renderDay method can't find the day to render

Upvotes: 0

Dmitriif
Dmitriif

Reputation: 2433

DatePicker has renderDay prop which we can use to customize the day cells of the calendar. It takes 3 arguments, the first one is the Date object, which we can use to compare with the array of dates that should be disabled:

  const dates = ["2022-05-08", "2022-05-11", "2022-05-19"];

  const customDayRenderer = (
    date: Date,
    selectedDates: Array<Date | null>,
    pickersDayProps: PickersDayProps<Date>
  ) => {
    const stringifiedDate = date.toISOString().slice(0, 10);
    if (dates.includes(stringifiedDate)) {
      return <PickersDay {...pickersDayProps} disabled />;
    }
    return <PickersDay {...pickersDayProps} />;
  };

  return (
    <LocalizationProvider dateAdapter={AdapterDateFns}>
      <DatePicker
        label="Basic example"
        value={value}
        onChange={(newValue) => {
          setValue(newValue);
        }}
        renderInput={(params) => <TextField {...params} />}
        renderDay={customDayRenderer}
      />
    </LocalizationProvider>
  );

Demo

Upvotes: 1

Related Questions