Create Simple DatePicker Component in Blazor
ASP.NET Core Blazor allows you to develop client side web applications using
HTML, Razpr, and C#. A typical Blazor application consists of one or more Razor
components. A Razor component physically exists as .razor file and contains a
mix of HTML markup, Razor constructs, and C# code. A Razor component can either
be used as if it is a page or it can be housed inside other component. If you
are beginner in Blazor it's worthwhile to learn some fundaments of building
Blazor components. That's what this article is about.
In this article you will develop a simple Razor component called DatePicker.
We won't be developing a fancy, feature rich popup DatePicker, we will rather
build a simple one as shown below, and focus more on learning the basics of
component development in Blazor. Although most of the modern browsers support
HTML5 DatePicker user interface, this simple DatePicker will help you understand
basics such as creating components, using components, setting component
properties, handling events, and two-way data binding.
This is how our DatePicker is going to look like:
Ok. Let's get going.
Begin by creating a new Blazor Server app using Visual Studio.
And then pick Blazor Server project template.
Once the application is created, add Components folder under Shared. Then add
a new Razor component named DatePicker to it. You can do that using Add New Item
dialog shown below.
Components that are intended to be used as pages reside under Pages folder
whereas components intended to be used by other components or pages can be kept
in any folder. In this case we keep DatePicker component in Shared > Components
folder.
Next, open DatePicker.razor file in Visual Studio and the following code to
its @code block.
@code {
public int Day { get; set; }
public int Month { get; set; }
public int Year { get; set; }
public string[] Months { get; set; } = {
"January", "February", "March",
"April", "May", "June", "July",
"August", "September", "October",
"November", "December" };
}
The @code block holds the code required by the component. It could be
properties, member variables, or methods. In this case we declare four
properties namely Day, Month, Year, and Month. The Month property holds an array
of month names. These properties are used in the component's markup. So, add the
following markup below the @code block.
<select @bind="Day">
@for (int i = 1; i <= 31; i++)
{
<option>@i</option>
}
</select>
<select @bind="Month">
@for (int i = 1; i <= 12; i++)
{
<option value="@i">@Months[i-1]</option>
}
</select>
<select @bind="Year">
@for (int i = DateTime.Now.Year-5;
i <= DateTime.Now.Year + 5; i++)
{
<option>@i</option>
}
</select>
<button type="button">Select</button>
The above markup consists of three <select> elements for displaying day,
month, and year respectively. There is also a button to indicate that a date has
been selected. Notice how Day, Month, and Year properties are used in the markup
using @bind syntax. Using @bind as shown here ensures that the value of Day /
Month / Year is assigned to the value DOM property of the respective <select>
element. While filling the month dropdown list we display month names but assign
month number as an <option> value. While filling the year dropdown list, 10
years are filled - five before the current year and five after the current year.
Save DatePicker.razor file. You will visit this file again later while adding
more functionality.
Now, add another Razor component named DatePickerHost.razor inside the Pages
folder. This component is intended to house the DatePicker component. Open
DatePickerHost.razor and add @page directive at the top:
@page "/datepickerhost"
The @page directive indicates that this Razor component is to be used as a
page. The @page directive also specifies a route where the page will be
accessible - /datepickerhost.
Then open _Imports.razor file and add the following namespace entry there:
@using BlazorComponentDemo.Shared.Components
We need this entry because our DatePicker component resides in the above
namespace. Adding this entry will make it accessible to the DatePickerHost.
Then place the DatePicker component in the DatePickerHost as shown below:
<DatePicker></DatePicker>
As you can see, you used the DatePicker component as it it is markup element.
Run the application, go to the browser's address bar and navigate to /datepickerhost.
This will display the DatePicker as shown below.
As you can see the DatePicker is empty when displayed in the browser. Let's
fix this by showing current date in it by default.
Go to DatePicker.component and add this code:
protected override void OnInitialized()
{
Day = DateTime.Now.Day;
Month = DateTime.Now.Month;
Year = DateTime.Now.Year;
}
Here, you are overriding OnInitialized() method. This method indicates that
the component has been initialized and can be used to perform some
initialization tasks. Here we assign certain default values to the Day, Month,
and Year properties.
If you run the application again this time it will show current date in the
DatePicker.
Now we are able to display current date in the DatePicker. But wouldn't it be
nice if the DatePickerHost is also allowed to specify a default date to be
displayed? Let's add that functionality.
Go to DatePicker component and add a public property named InitialDate as
shown below:
[Parameter]
public DateTime InitialDate { get; set; }
Notice that the InitialDate property is decorated with [Parameter] attribute.
The [Parameter] attribute marks the property to be the component's parameter -
something that can be set from the external world.
Also add the following code in the OnInitialized() method:
protected override void OnInitialized()
{
Day = InitialDate.Day;
Month = InitialDate.Month;
Year = InitialDate.Year;
}
Now, go to DatePickerHost component and add a property there called
DefaultDate.
public DateTime DefaultDate { get; set; }
And assign some date to this property in DatePickerHost's OnInitialized()
method.
protected override void OnInitialized()
{
DefaultDate = new DateTime(2019, 9, 2);
}
Finally, set the DatePicker components InitialDate parameter like this:
<DatePicker InitialDate="DefaultDate"></DatePicker>
If you run the application you will get this output.
So far so good. Currently even if you select some values in the three
dropdown lists and hit the Select button, nothing special happens. When a user
clicks on the Select button, we would like to notify the parent (DatePickerHost)
about the changed date. This way the parent component can read the DatePicker
value and take some action on that. This calls for raising an event from the
DatePicker and handling it in the DatePickerHost.
Let's add that piece of functionality.
Go to DatePicker component and are an event as shown below:
[Parameter]
public EventCallback<DateTime> DateSelected
{ get; set; }
Here, you defined an event callback named DateSelected. This callback will
supply the selected DateTime to the event handler function. This is just event
declaration. You need to raise this event when the Select button is clicked. To
do so add the following method in the @code block of DatePicker.
public Task OnSelectClick()
{
DateTime dt = new DateTime(Year, Month, Day);
return DateSelected.InvokeAsync(dt);
}
This code grabs the day, month, and year selected in the three dropdown lists
and gets the DateTime value. It then raises the DateSelected event by calling
InvokeAsync() and by passing the DateTime to it. Note that OnSelectClick()
method returns a Task since InvokeAsync() is an asynchronous operation.
The OnSelectClick() should get called when a user clicks on the Select
button. You can wire it to the click event of the button like this:
<button type="button"
@onclick="OnSelectClick">Select</button>
As you can see, @onclick syntax wires OnSelectClick() method to be the click
event handler of the button.
Next, you need to handle the DateSelected event of the DatePicker component
in DatePickerHost. So, go to DatePickerHost and modify the DatePicker markup
like this:
<DatePicker
InitialDate="DefaultDate"
DateSelected="OnDateSelected">
</DatePicker>
The above markup specifies that the DateSelected event of the DatePicker will
be handled by OnDateSelected() method written inside DatePickerHost. The
OnDateSelected() method is shown below:
public void OnDateSelected(DateTime dt)
{
SelectedDate = dt;
}
The OnDateSelected() event handler receives the DateTime selected in the
DatePicker. Inside, it assigns the DateTime to SelectedDate property so that it
can be used for further processing. The SelectedDate property of DatePickerHost
looks like this:
public DateTime SelectedDate { get; set; }
For the sake of testing we will output the value of SelectedDate in
DatePickerHost by adding this markup:
<h3>Selected Date : @SelectedDate</h3>
Run the application, select some values in the three dropdown lists, and hit
the Select button. You should see the selected date rendered below the
DatePicker.
In the preceding example, you are able to set the initial date in the
DatePicker and also get notified when date selection changes. What if we want to
have two-way data binding? By two-way data binding it means that changes to the
selected date are propagated from DatePickerHost to DatePicker and vice a versa.
Open DatePicker component and add one more parameter property called
SelectedDate.
[Parameter]
public DateTime SelectedDate
{
get {
return new DateTime
(Year, Month, Day);
}
set {
Day = value.Day;
Month = value.Month;
Year = value.Year;
}
}
Notice the code in set block. It simply assigns the Day, Month, and Year
properties to the respective parts of the specified DateTime.
Also add one more event to DatePicker called SelectedDateChanged
[Parameter]
public EventCallback<DateTime>
SelectedDateChanged { get; set; }
Then change the OnSelectClick() method as shown below:
public Task OnSelectClick()
{
SelectedDate = new DateTime
(Year, Month, Day);
return SelectedDateChanged.
InvokeAsync(SelectedDate);
}
This code should look familiar to you since you used it before. The only
difference here is that you raise SelectedDateChanged event.
Now, open DatePickerHost and assign the SelectedDate property in the
OnInitialized() method.
protected override void OnInitialized()
{
SelectedDate = DateTime.Now;
}
The SelectedDate property will be data bound with DatePicker so that any
changes to it will be reflected in the DatePicker component. For example, after
setting current date to SelectedDate property as shown above the DatePicker
dropdown lists will reflect this date value.
To confirm that any change to SelectedDate is propagated to the DatePicker
add a button at the end of DatePickerHost like this:
<button type="button"
@onclick="OnSetDateClick">Set Date</button>
The Set Date button when clicked simply changes the value of SelectedDate
property. The OnSetDateClick() event handler looks like this:
public void OnSetDateClick()
{
SelectedDate = new DateTime(2019, 11, 2);
}
Here, the code simply sets some different date to the SelectedDate property.
Now, modify the <DatePicker> markup as shown below:
<DatePicker @bind-SelectedDate="@SelectedDate">
</DatePicker>
Notice the code shown in bold letters. It performs two-way data binding
between SelectedDate property of DatePicker and SelectedDate property of
DatePickerHost.
Run the application and observe the output. The following figure shows the
initial run of the application.
Notice that the dropdown lists reflect the date assigned to DatePickerHost's
SelectedDate property.
Then change the date selection in the dropdown lists and click on the Select
button. You will find that the message correctly displays the newly selected
date.
This proves that any change to DatePicker's SelectedDate property is
reflected in DatePickerHost's SelectedDate property.
Now, click on the Set Date button that sets DatePickerHost's SelectedDate
property to a new value. After doing that, the dropdown lists should reflect the
changed date.
Thus any changes to the SelectedDate properties are synchronized between the
DatePicker and DatePickerHost.
That's it for now! Keep coding!!