Recently I was working on improving the UI of a web form a colleague had developed and one of the requirements was to have a Calender control to select the year for which the data in the form should be filtered. I knew that this had to be done by using the Calendar extender control offered by the AJAX Control Toolkit  but just didn’t know how.

The problem was that the Calender extender by default operates at the days level. This means that normally when the control is shown it’ll be showing the days in the months and even if this could be changed to show just the years selecting the year would just drill down to month and selecting a month to days and the selection would be mad at that level.

After a couple of hours of looking around in the net I came across this great post in Agha Usman Ahmed’s Blog which had what I wanted exactly but at the month level. With very little modification I was able to adopt it to my requirement.

The solution to the problem was to switch the mode of the calendar to year using an available method and the attach a click event to each item. This way when a year is selected it fires a click event and the drill down to the month doesn’t happen.

The following is the code I’ve used with a brief explanation

<form id="form1" runat="server">
    <div>
     <asp:TextBox ID="YearBox" runat="server"></asp:TextBox>
     <asp:CalendarExtender ID="TextBox1_CalendarExtender" runat="server" OnClientHidden="onCalendarHidden"
        OnClientShown="onCalendarShown" BehaviorID="calendar1" Enabled="True" TargetControlID="YearBox" Format="yyyy">
      </asp:CalendarExtender>
      <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
      </asp:ToolkitScriptManager>
     </div>
 </form>

As seen by the above source code I used an AJAX calendar extender control when given a target control such as a text box would render a calendar control when that control is selected. (If you don’t have the AJAX control toolkit installed click here to get  the .dll).

The format option has been set to “yyyy” so that when a year is selected this would set the text in the target control to the year with that format.

A behavior ID has been given to the calendar extender so that its client end behavior can be easily accessed by client side code.

The client side code in this case is three cool JavaScript methods  that together will attach/detach  click events to the year items of the calendar achieving our requirement.

The onCalendarShown method shown below adds a click event to each year item while its partner onCalendarHidden detaches the click events once the calendar is hidden


function onCalendarShown() {

  var cal = $find("calendar1");
  //Setting the default mode to year
  cal._switchMode("years", true);

 //Iterate every year Item and attach click event to it
  if (cal._yearsBody) {
   for (var i = 0; i < cal._yearsBody.rows.length; i++) {
    var row = cal._yearsBody.rows[i];
     for (var j = 0; j < row.cells.length; j++) {
      Sys.UI.DomEvent.addHandler(row.cells[j].firstChild, "click", call);
     }
   }
 }
}


function onCalendarHidden() {
  var cal = $find("calendar1");
  //Iterate every month Item and remove click event from it
  if (cal._yearsBody) {
   for (var i = 0; i < cal._yearsBody.rows.length; i++) {
    var row = cal._yearsBody.rows[i];
    for (var j = 0; j < row.cells.length; j++) {
     Sys.UI.DomEvent.removeHandler(row.cells[j].firstChild, "click", call);
    }
  }
 }
}

Both these methods call a third method ‘call’ which takes the selected year and raises the date selection changed event which will get the selected date set to the text box


function call(eventElement) {
 var target = eventElement.target;
 switch (target.mode) {
  case "year":
   var cal = $find("calendar1");
   cal._visibleDate = target.date;
   cal.set_selectedDate(target.date);
   cal._switchMonth(target.date);
   cal._blur.post(true);
   cal.raiseDateSelectionChanged();
   break;
 }
}

try it out and see how it works. for a preview of the original version check out Agha Usman Ahmed’s Blog

Enjoy 🙂