Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / Blazor

Blazor datepicker Component using JQuery

5.00/5 (3 votes)
6 Jun 2021CPOL3 min read 16.5K  
Custom JQuery datepicker component using Blazor
This article shows how to build a custom JQuery datepicker using .NET Blazor.

Introduction

In one of my assignments where we were using Blazor.net, few of the forms had input control as date picker calendar. The custom requirement as per the business logic was not possible to be implemented using the current Blazor InputDate component in EditForm. Listed below is some of the logic which restricted using the default component:

  1. Restrict date like Start Date and End Date or else restrict future or past date
  2. Input field formatting

The above points can be achieved in the future release but to fulfill the development, we opted to use Jquery. Having knowledge of using Blazor to restrict the use of JavaScript in application, the current release does not fully satisfy the development material. Hoping for the future release to update the same. We could use the third party component but were restricted due to some policies. Thus to clear the development blocker, we decided to make use of jquery datepicker and create a custom component that can be used throughout.

Below is the code for the same along with the explanation of how to use it in different scenarios.

Using the Code

The code works like a simple plugin by just configuring the component and using it in the application. Below is the code for the same.

_Host.cshtml

Provide reference to jquery library. Please note site.js is a custom js whose code is mentioned below:

HTML
<script src="js/Jquery-3.5.1.min.js"></script>
<script src="jquery-ui-1.12.1/jquery-ui.min.js"></script>
<script src="js/site.js"></script>

site.js

JavaScript
window.siteFunction={
    InitDatePickerwithSelect: function (element, formatDate, minDate, maxDate) {
        $(element).datepicker('destroy');
        $(element).datepicker({
            showOtherMonths: true,
            selectOtherMonths: true,
            changeMonth: true,
            changeYear: true,
            dateFormat: formatDate,
            minDate: minDate == null ? null : new Date(minDate),
            maxDate: maxDate == null ? null : new Date(maxDate),
            onSelect: function (date) {
                var myElement = $(this)[0];
                var event = new Event('change');
                myElement.dispatchEvent(event);
            }
        });
    },
    SetMinMaxDate: function (element, minDate, maxDate) {
        var min = minDate == null ? null : new Date(minDate);
        var max = maxDate == null ? null : new Date(maxDate);
        $(element).datepicker('option', 'minDate', min);
        $(element).datepicker('option', 'maxDate', max);
    }
}

JQDatePicker.razor

Create a razor component as per the below code at a shared UI folder of the project. For example, BlazorApp/Pages/Component.

Razor
<input type="text" id="@(Id)" class="form-control datepicker @(Class)" 
           data-provide="datepicker"
           disabled="@Disabled"
           @ref="currentElement"
           @bind-value="BindValue"
           @bind-value:event="oninput"
           @bind-value:format="@Format"
           @onchange="OnChange" />

JQDatePicker.razor.cs

Create a razor.cs class same as above in the same folder as that of razor component. The below code acts as a backend code for the razor page created.

C#
#region Microsoft References
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
#endregion

#region System References
using System;
using System.Threading.Tasks;
#endregion

namespace BlazorApp.Pages.Components
{
public partial class JQDatePicker{
        #region Parameter
        [Parameter] public DateTime? Value 
        { 
            get=>_value; 
            set
            {
                if(_value==value) return;

                _value=value;
                ValueChanged.InvokeAsync(Value);
             } 
        }
        [Parameter] public string Format { get; set; }
        [Parameter] public EventCallback<DateTime?> ValueChanged {get;set;}
        [Parameter] public string Id { get; set; }
        [Parameter] public string Class { get; set; }
        [Parameter] public bool Disabled { get; set; }
        [Parameter] public DateTime? MinDate { get; set; }
        [Parameter] public DateTime? MaxDate { get; set; }
        #endregion

        #region Inject
        [Inject] IJSRuntime JSRuntime { get; set; }
        #endregion
        private DateTime? _value ;
        private string DatePickerFormat { get; set; }
        ElementReference currentElement { get; set; }

        #region Protected Method
        /// <summary>
        /// Method to initialize variable on component initialization
        /// </summary>
        protected override async Task OnInitializedAsync()
        {
            Format = string.IsNullOrEmpty(Format) ? "dd/MMM/yyyy" : Format;
            DatePickerFormat = string.IsNullOrEmpty(DatePickerFormat) ? 
                               "dd/M/yy" : DatePickerFormat;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="firstRender"></param>
        /// <returns></returns>
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
               await RenderDatePicker();
            }
            if (!firstRender)
               await SetMinMaxDate();
        }
        #endregion

        #region Private Method
        /// <summary>
        /// Method to invoke Date picker js function
        /// </summary>
        /// <returns></returns>
        private async Task RenderDatePicker()
        {
            await JSRuntime.InvokeVoidAsync("siteFunction.InitDatePickerwithSelect", 
                            currentElement, DatePickerFormat, MinDate, MaxDate);
        }
        /// <summary>
        /// Method to invoke setminmaxdate js function
        /// </summary>
        /// <returns></returns>
        private async Task SetMinMaxDate()
        {
            await JSRuntime.InvokeVoidAsync("siteFunction.SetMinMaxDate", 
                                             currentElement, MinDate, MaxDate);
        }
        /// <summary>
        /// Method to handle date picker change
        /// </summary>
        /// <param name="e">ChangeEventArgs</param>
        private void OnChange(ChangeEventArgs e)
        {
            DateTime dateTime;
            if (DateTime.TryParse(e.Value.ToString(), out dateTime))
            {
                ValueChanged.InvokeAsync(dateTime);
            }
        }
        #endregion
   }
}

Below is the description of each and every variable and function:

Component Attribute Description
Value The model property to be passed
Format UI Format of the UI component
ValueChanged Event call back which sets the model property on change of the value. This helps in two way binding
Id id attribute of the component to be set
Class class attribute of the component to be set
Disabled disable attribute to be set, i.e., disabled if true else enabled
MinDate attribute to be set in case to restrict past dates. If null or not set, then calendar won't restrict past date
MaxDate attribute to be set in case to restrict future dates. If null or not set, then calendar won't restrict future date

 

Variable Description
DatePickerFormat Format to be set for jquery datepicker. Kept as configurable, but can be changed to a parameter.
currentElement variable to pass DOM element reference

 

Method Description
OnInitializedAsync Method to be executed on initialization of the component
OnAfterRenderAsync Method to be executed everytime the component is rendered
RenderDatePicker Method to call JavaScript function that sets the jquery datepicker
SetMinMaxDate Method to call JavaScript function that sets the min and max date of the datepicker
OnChange Method to be called on change of the input field

How to Use?

Below is the set of sample code that shows how to use the above component using two way binding.

DatePicker.razor

Below is the sample code that displays how to use the able component.

Razor
@page "/datepicker"
<div class="container">
    <div class="col-12">
        <div class="row">
            <div class="form-group">
                <label for="txtStartDate">Start Date</label>
                <JQDatePicker Id="txtStartDate" BindValue="@StartDate"
                    MaxDate="@EndDate"
                    Format="dd/MMM/yyyy"
                    >
                    </JQDatePicker>
            </div>
        </div>
            <div class="row">
            <p>Start Date : @StartDate</p>
        </div>
    </div>
</div>

@code{
        private DateTime? StartDate{get;set;}
        private DateTime? EndDate{get;set;}
}

Below is the sample code that displays how to use Min Max date functionality:

Razor
            <div class="form-group">
                <label for="txtStartDate">Start Date</label>
                <JQDatePicker Id="txtStartDate" BindValue="@StartDate"
                    MaxDate="@EndDate"
                    Format="dd/MMM/yyyy"
                    >
                    </JQDatePicker>
            </div>
            <div class="form-group">
                <label for="txtEndDate">End Date</label>
                <JQDatePicker Id="txtEndDate" BindValue="@EndDate"
                    MinDate="@StartDate"
                    Format="dd/MMM/yyyy"
                    >
                    </JQDatePicker>
            </div>
            <div class="row">
                 <p>Start Date : @StartDate</p>
            </div>
            <div class="row">
                 <p>End Date : @EndDate</p>
            </div>
@code{
        private DateTime? StartDate{get;set;}
        private DateTime? EndDate{get;set;}
}

The sample code is available on GitHub.

If any of the readers have an improved and better workflow for the above requirement, I would like to add the same to my knowledge.

CODE IT !!!

History

  • 20th December, 2020: Initial version
  • 6th June, 2021: Updated article with two way binding implementation of the component

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)