blazort_870x220

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>

Retrieving a Single Date

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.

Retrieving Multiple Dates

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.

Working with Disabled Dates and Date Ranges

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
About the Author

Peter Vogel

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.

Related Posts

Comments

Comments are disabled in preview mode.