The Calendar component for Telerik UI for Blazor gives your users an intuitive way to select a single date, but it also supports the standard UI conventions for selecting multiple dates. Here’s how to handle all of those scenarios, including those times you want to exclude some dates.
In a previous column, I showed how to add the Telerik UI for Blazor Calendar
component to a page and support the user navigating from month-to-month. But I didn’t spend much time describing how to grab the date the user selects. That’s the point of this post: The options you have for letting the user select both a single date and multiple dates.
Version caveats: For this column, I’m using Telerik UI for Blazor 1.4.1, Visual Studio 2019 Preview (version 16.3), and ASP.NET Core v3.0.0-preview7. I had to install the NuGet package for Microsoft.CodeAnalysis
(and update some related packages) before I could install the NuGet package containing Telerik UI for Blazor. I also had to upgrade to the latest version of the JavaScript file that supports its components:
<script src="https://kendo.cdn.telerik.com/blazor/1.4.1/telerik-blazor.min.js" defer></script>
The Calendar
component provides you with three ways to retrieve a single date. If you don’t need to work with the date immediately, the simplest solution is to simply bind the calendar’s value to a property or field in your application using the @bind-Value
attribute. Binding the <TelerikCalendar>
element to a field might look like this:
<TelerikCalendar @bind-Value="startDate"></TelerikCalendar>
@code {
private DateTime startDate;
// ...
}
With this solution, every time the user selects a date, the startDate
field will automatically be updated with the user’s selected date.
While there’s nothing wrong with using a field, rewriting the code as a fully implemented property and putting some code in the property’s setter allows you to take some action when the user selects a date. Replacing this field with a fully-implemented startDate
property lets me put the selected date somewhere safe (in the following code, I just store the value in a backing field).
Here’s the code that lets me hang onto the user’s last selected value no matter what happens in my component’s UI (notice that I don’t have to rewrite the @bind-Value
attribute on the <TelerikCalendar>
element to work with this code because the calendar doesn’t care if I’m binding to a field or a property):
private DateTime _startDate;
private DateTime startDate
{
get { return _startDate; }
set { _startDate = value; }
}
Another option for having some code to run as soon as the user selects a date is to bind a method of your own to the calendar’s ValueChanged()
event. The method bound to the event will be passed a DateTime
object representing the user’s selected date whenever the user clicks on a date.
Here’s the code that does that (and also just stashes the date in a field):
<TelerikCalendar ValueChanged="@getDate"></TelerikCalendar>
@code {
private DateTime _startDate;
private void getDate(DateTime startDate)
{
_startDate = startDate;
}
}
These two options are mutually exclusive: You can’t use both @bind-Value
and ValueChanged()
on the same <TelerikCalendar>
element.
Your third option is to bind the calendar as a whole to a field in your component. Then, in any method in your component, you just have check the calendar’s Value
property to retrieve the user’s selected date. This code, for example, grabs the user’s date in a method bound to a button’s onclick()
event:
<TelerikCalendar @ref="calendar"></TelerikCalendar>
<br />
<TelerikButton ButtonType="ButtonType.Button"
@onclick="sendData">
Update
</TelerikButton>
@code {
TelerikCalendar calendar;
public void sendData()
{
_startDate = calendar.Value;
// perform other actions...
}
}
This option can be combined with either @bind-Value
or ValueChanged
attributes.
There are occasions when you will want to let the user select multiple dates. A typical scenario is when the user must specify a range of dates by specifying a start and end date. However, there are also scenarios where you want the user to select multiple, random dates ("Please indicate which dates there will be someone home to accept delivery").
The Calendar
component supports both scenarios – you just turn on multiple date selection for the calendar by setting its SelectionMode
attribute to CalendarSelectionMode.Multiple
:
<TelerikCalendar SelectionMode="@CalendarSelectionMode.Multiple">
</TelerikCalendar>
There is a UI trick here, though: As with dropdown lists or listboxes, the user must press the Ctrl key (to select multiple dates) or the Shift key (to select a range of dates) when selecting a date.
If you use the calendar’s ValueChanged
attribute to bind to a method, your method will be called each time the user selects a date and the method will be passed the date the user clicked. If you use the @bind-Value
attribute, your property or field will also be set to the date the user clicked on each time the user selects a date. You could use these two options to validate dates as the user selects them.
When it comes to retrieving all the selected dates, however, the simplest solution is to add a reference to the calendar component and access all the selected dates using the SelectedDates
property:
<TelerikCalendar @ref="calendar"
SelectionMode="@CalendarSelectionMode.Multiple">
</TelerikCalendar>
<br />
<TelerikButton ButtonType="ButtonType.Button" @onclick="sendData">
Update
</TelerikButton>
@code {
TelerikCalendar calendar;
private void sendData()
{
foreach (DateTime dt in calendar.SelectedDates)
{
// work with each of the selected dates...
}
}
}
If the user has the Ctrl key pressed while selecting dates, the SelectedDates
collection will hold all of the dates the user clicked on. If the user has the Shift key pressed while selecting dates, then the SelectedDates
collection will hold all of the dates between the two selected dates.
Be aware, though: If you’re also using the DisabledDates
property and the user uses the Shift key to select a range of dates, some special handling is required.
The DisabledDates
property allows you to specify a collection of dates that the user is not allowed to select. Here’s a naïve implementation that adds the weekends in July 2019 to a collection:
private List<DateTime> weekends = new List<DateTime>() {
new DateTime(2019, 7, 6),
new DateTime(2019, 7, 7),
/* other weekend dates */
};
The weekends
collection could then be tied to a <TelerikCalendar>
element using the DisabledDates
attribute to prevent the user from clicking on weekend dates:
<TelerikCalendar @ref="calendar"
SelectionMode="@CalendarSelectionMode.Multiple"
DisabledDates="@weekends">
</TelerikCalendar>
However, when the user uses the Shift key to select a range of dates, they may never even try to click on any of the disabled dates – a user might, for example, click on the Friday before the weekend (July 5th) and the Monday following (July 8th). The calendar’s UI will do its bit, highlighting the full range (from the 5th to the 8th inclusive), while using a duller color for the disabled dates. The SelectedDates
collection will, however, include all the dates in the range, including the disabled dates (i.e. July 5th, 6th, 7th, and 8th).
Fortunately, removing disabled dates is easy: Just apply the Except()
method to the SelectedDates
property, passing the collection of disabled dates (the weekends
collection, in my case). The Except()
method will return a new collection consisting of the dates from SelectedDates
that don’t appear in the disabled dates collection. If you want, instead, to get a list of the disabled dates in SelectedDates
– to notify the user about which dates in the range weren’t selected – you would use the Intersect()
method instead of the Except()
method (though, as I say, the UI does a pretty good job of flagging the disabled dates).
Revising my sendData()
method to automatically remove any disabled dates gives me this:
public void sendData()
{
var validDates = calendar.SelectedDates.Except(weekends);
foreach (DateTime dt in validDates)
{
// ...
}
}
You can now give your users the ability to select the date (or dates) they want while preventing them from selecting the date (or dates) you don’t want them to use.
To learn more about these Telerik UI for Blazor components and what they can do, check out this Blazor demo page or download a trial to start developing right away!
Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter also writes courses and teaches for Learning Tree International.