Skip to content

Commit 79b466a

Browse files
committed
feat: add disabled dates API to date and date-time pickers
Add server-side disabled-dates support: setDisabledDates for a fixed list, setDisabledWeekdays, and a DisabledDatesProvider callback that is called per date. The connector composes these into the web component's disabledDatesProvider (static rules client-side, the provider via a @ClientCallable range request evaluated per date on the server) and the validator rejects disabled values. DateTimePicker delegates the same API to its date part. Part of #2867
1 parent fe7f085 commit 79b466a

9 files changed

Lines changed: 905 additions & 0 deletions

File tree

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2000-2026 Vaadin Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package com.vaadin.flow.component.datepicker;
17+
18+
import java.time.LocalDate;
19+
import java.util.List;
20+
21+
import com.vaadin.flow.component.datepicker.DatePicker.DatePickerI18n;
22+
import com.vaadin.flow.component.html.Div;
23+
import com.vaadin.flow.component.html.Paragraph;
24+
import com.vaadin.flow.router.Route;
25+
26+
/**
27+
* Test page for a date picker that combines the two disabled-dates APIs: a
28+
* fixed list of disabled dates and a per-date provider. January 2023 is shown,
29+
* with January 10th and 20th disabled through the fixed list, and the 15th of
30+
* every month disabled through the provider.
31+
*/
32+
@Route("vaadin-date-picker/date-picker-disabled-dates")
33+
public class DatePickerDisabledDatesPage extends Div {
34+
35+
public static final int PROVIDER_DISABLED_DAY = 15;
36+
public static final List<LocalDate> FIXED_DISABLED_DATES = List
37+
.of(LocalDate.of(2023, 1, 10), LocalDate.of(2023, 1, 20));
38+
39+
public DatePickerDisabledDatesPage() {
40+
DatePicker datePicker = new DatePicker();
41+
datePicker.setId("date-picker");
42+
datePicker.setI18n(new DatePickerI18n()
43+
.setDateDisabledErrorMessage("Date is not available"));
44+
// Show January 2023 when the overlay opens.
45+
datePicker.setValue(LocalDate.of(2023, 1, 5));
46+
47+
// Fixed list of already-booked dates.
48+
datePicker.setDisabledDates(FIXED_DISABLED_DATES);
49+
// Provider: the 15th of every month.
50+
datePicker.setDisabledDatesProvider(date -> {
51+
System.out.println("Checking " + date);
52+
return date.getDayOfMonth() == PROVIDER_DISABLED_DAY;
53+
});
54+
55+
add(new Paragraph(
56+
"Disabled: January 10 and 20, 2023 (fixed list); the 15th of every month (provider)."),
57+
datePicker);
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright 2000-2026 Vaadin Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package com.vaadin.flow.component.datepicker;
17+
18+
import java.time.LocalDate;
19+
20+
import org.junit.Assert;
21+
import org.junit.Before;
22+
import org.junit.Test;
23+
24+
import com.vaadin.flow.component.datepicker.testbench.DatePickerElement;
25+
import com.vaadin.flow.component.datepicker.testbench.DatePickerElement.MonthCalendarElement;
26+
import com.vaadin.flow.testutil.TestPath;
27+
import com.vaadin.tests.AbstractComponentIT;
28+
29+
@TestPath("vaadin-date-picker/date-picker-disabled-dates")
30+
public class DatePickerDisabledDatesIT extends AbstractComponentIT {
31+
32+
private DatePickerElement datePicker;
33+
34+
@Before
35+
public void init() {
36+
open();
37+
datePicker = $(DatePickerElement.class).id("date-picker");
38+
}
39+
40+
@Test
41+
public void openOverlay_fixedAndProviderDatesAreDisabled() {
42+
datePicker.open();
43+
44+
MonthCalendarElement january = getJanuary2023();
45+
// The provider resolves asynchronously; wait for the 15th to become
46+
// disabled once the result arrives.
47+
waitUntil(driver -> january.isDateDisabled(
48+
DatePickerDisabledDatesPage.PROVIDER_DISABLED_DAY));
49+
50+
// Fixed disabled dates (January 10 and 20).
51+
Assert.assertTrue("January 10 (fixed) should be disabled",
52+
january.isDateDisabled(10));
53+
Assert.assertTrue("January 20 (fixed) should be disabled",
54+
january.isDateDisabled(20));
55+
Assert.assertFalse("An unaffected date should remain enabled",
56+
january.isDateDisabled(
57+
DatePickerDisabledDatesPage.PROVIDER_DISABLED_DAY + 1));
58+
}
59+
60+
@Test
61+
public void selectProviderDisabledDate_fieldIsInvalid() {
62+
datePicker.setDate(LocalDate.of(2023, 1,
63+
DatePickerDisabledDatesPage.PROVIDER_DISABLED_DAY));
64+
Assert.assertTrue("A provider-disabled date should be invalid",
65+
datePicker.getPropertyBoolean("invalid"));
66+
67+
datePicker.setDate(LocalDate.of(2023, 1,
68+
DatePickerDisabledDatesPage.PROVIDER_DISABLED_DAY + 1));
69+
Assert.assertFalse("An enabled date should be valid",
70+
datePicker.getPropertyBoolean("invalid"));
71+
}
72+
73+
@Test
74+
public void selectFixedDisabledDate_fieldIsInvalid() {
75+
datePicker.setDate(LocalDate.of(2023, 1, 10));
76+
Assert.assertTrue("A fixed disabled date should be invalid",
77+
datePicker.getPropertyBoolean("invalid"));
78+
79+
datePicker.setDate(LocalDate.of(2023, 1, 11));
80+
Assert.assertFalse("An enabled date should be valid",
81+
datePicker.getPropertyBoolean("invalid"));
82+
}
83+
84+
private MonthCalendarElement getJanuary2023() {
85+
return datePicker.getOverlayContent().getVisibleMonthCalendars()
86+
.stream()
87+
.filter(calendar -> "January 2023"
88+
.equals(calendar.getHeaderText()))
89+
.findFirst().orElseThrow(() -> new AssertionError(
90+
"January 2023 month calendar not found"));
91+
}
92+
}

0 commit comments

Comments
 (0)