Introduction
If you have ever had to make a hotel reservation on line you may have seen this functionality. Basically there is a field for a check-in date and there is also a field for a check-out date. Typically the websites have cool popup windows with a calendar in it that when selected, the text field is automatically updated with the chosen date. It then gets a little bit more complicated because usually when you select the check in date, the check out-date is automatically updated also.
Let's take a look at how to a this with ASP.AJAX and the Ajax Control Toolkit CanderExtender.
The Mark Up
32 <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
33 <ContentTemplate>
34 <div class="DatePanel">
35 <table>
36 <tr>
37 <td>
38 from date:
39 <asp:TextBox runat="server" ID="txtFromDate" onFocus="javascript:this.blur();" Width="80"
40 autocomplete="off" AutoPostBack="true" OnTextChanged="txtFromDate_TextChanged" />
41 <asp:ImageButton runat="Server" ID="Image1" ImageUrl="~/images/Calendar_scheduleHS.png"
42 AlternateText="Click to show calendar" /><br />
43 <cc1:CalendarExtender ID="calendarButtonExtender" runat="server" TargetControlID="txtFromDate"
44 PopupButtonID="Image1" />
45 <asp:RangeValidator ID="RangeValidatorFromDate" runat="server" ErrorMessage="Please enter a date a greater than or equal today's date"
46 ControlToValidate="txtFromDate" Type="Date"></asp:RangeValidator>
47 </td>
48 <td>
49 to date:
50 <asp:TextBox runat="server" ID="txtToDate" onFocus="javascript:this.blur();" Width="80"
51 autocomplete="off" OnTextChanged="txtToDate_TextChanged" AutoPostBack="true"/>
52 <asp:ImageButton runat="Server" ID="Image2" ImageUrl="~/images/Calendar_scheduleHS.png"
53 AlternateText="Click to show calendar" /><br />
54 <cc1:CalendarExtender ID="CalendarExtender1" runat="server" TargetControlID="txtToDate"
55 PopupButtonID="Image2" />
56 <asp:RangeValidator ID="RangeValidatorToDate" runat="server" ErrorMessage="Please enter a date a greater than or equal today's date."
57 ControlToValidate="txtToDate" Type="Date"></asp:RangeValidator>
58 </td>
59 </tr>
60 </table>
61 <br />
62 <br />
63 </div>
64 </ContentTemplate>
65 <Triggers>
66 <asp:AsyncPostBackTrigger ControlID="txtFromDate" EventName="TextChanged" />
67 <asp:AsyncPostBackTrigger ControlID="txtToDate" EventName="TextChanged" />
68 </Triggers>
69 </asp:UpdatePanel>
The textbox could be wired many different ways, but here is what I did.
- First off, I set the OnFocus property to blur. This blocks the user's from entering a date in the texbox directly. I did not want the user to have the ability to enter an incorrectly formated date, so I am only allowing them to enter the date only by using the calendar control.
- Because I want to update the "to date" when the text changes in the "from date", I have set the OnTextChange event to fire which will map to our function that will do the update. I have also set the AutoPostback property to true, so it knows to make a postback. Because we also have this event mapped to UpdatePanel trigger, it will do an asynchronous call to the function causing only this section of the page to update.
- The ImageButton will fire the popup calendar.
- The CalendarExtender control them maps the Textbox and the ImageButton so they work in tandom. Because I am using an ImageButton, the calendar will automatically disappear when the date is selected.
- I have a RangeValidator that basically checks to make sure the date is not before today's date.
- The same thing is then done for the "to date" controls.
- All of this is then wrapped by an UpdatePanel (note: make sure you set the ToolScriptManager to enable partial rendering and you also set the UpdatePanel's UdateMode to "Conditional" for better performance).
- The triggers are then set to asynchronously post back when text changes.
The Page_Load Event
I would definatelly refactor this code later but for simplicity sake I am just puttong the code right on the page load event.
19 protected void Page_Load(object sender, EventArgs e)
20 {
21 if (!Page.IsPostBack)
22 {
23 RangeValidatorFromDate.MinimumValue = DateTime.Today.ToShortDateString();
24 RangeValidatorFromDate.MaximumValue = DateTime.MaxValue.ToShortDateString();
25 RangeValidatorToDate.MinimumValue = DateTime.Today.ToShortDateString();
26 RangeValidatorToDate.MaximumValue = DateTime.MaxValue.ToShortDateString();
27 txtFromDate.Text = DateTime.Today.ToShortDateString();
28 txtToDate.Text = DateTime.Today.AddDays(30).ToShortDateString();
29
30 }
31
32
33 }
Here all I am doing is setting the RangeValidator exception rules, and I also setting the default date to be today and 30 days from now.
The Text Change Events
35 protected void txtFromDate_TextChanged(object sender, EventArgs e)
36 {
37 DateTime fromDate = Convert.ToDateTime(txtFromDate.Text);
38
39 if (fromDate >= DateTime.Today)
40 txtToDate.Text = fromDate.AddDays(30).ToShortDateString();
41 else
42 {
43 txtFromDate.Text = DateTime.Today.ToShortDateString();
44 RangeValidatorFromDate.IsValid = false;
45
46 }
47 }
48
49 protected void txtToDate_TextChanged(object sender, EventArgs e)
50 {
51 DateTime toDate = Convert.ToDateTime(txtToDate.Text);
52 DateTime fromDate = Convert.ToDateTime(txtFromDate.Text);
53
54 if (toDate < fromDate && toDate >= DateTime.Today)
55 txtFromDate.Text = toDate.ToShortDateString();
56 else
57 {
58 if (toDate < DateTime.Today)
59 {
60 txtFromDate.Text = DateTime.Today.ToShortDateString();
61 txtToDate.Text = DateTime.Today.AddDays(30).ToShortDateString();
62 RangeValidatorToDate.IsValid = false;
63 }
64 }
65
66 }
- When the "from date" is selected, I want to change the "to date" to be 30 days from now. If the date is less than today, I want to set the "to date" back to today.
- When the "to date" is selected, if it is less than the "from date", then I want to set the "from date" to be the same date. If the "to date" is less than today's date, then I want warn the user and set the dates back to the default dates.
Not too difficult.