ASP.NET MVC Calendar
I was creating booking system for one of my clients, everything went pretty smooth until he asked for calendar that would display the dates that are unavailable to pick, booked but not confirmed yet and booked and confirmed – all these in different styles. After some research I did I’ve found that none of the tools like jquery or mootools plugins worked for me the way I wanted them to work. So I’ve decided to create my own Calendar user control.
Thinking what I would need I came to list of following variables :
- month/year to display
- number of days in month to display
- what day of week are the first and last day of month to display
Normally you would want this information to be part of Model / ViewModel but to make things simple we’ll put all of this into cshtml ( yeah, we’ll be using Razor and MVC3). First things first, so let’s create a new View in
/Views/Shared folder by name of “_ReservationCalendar.cshtml”
@{
DateTime firstDay = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
int daysInCurrentMonth = DateTime.DaysInMonth(firstDay.Year, firstDay.Month);
DateTime lastDay = new DateTime(Model.yearToShow, Model.monthToShow, daysInCurrentMonth);
// Sunday casted to int gives 0 but that will not work for us, we need 7 to be able to calculate number of empty cells correctly
int dayOfWeekFirst = ((int)firstDay.DayOfWeek > 0) ? (int)firstDay.DayOfWeek : 7;
int dayOfWeekLast = ((int)lastDay.DayOfWeek > 0) ? (int)lastDay.DayOfWeek : 7;
}
Okay, we’ve got all we need to start building HTML table for our calendar page. Let’s start with header.
<table id="reservationCalendar">
<thead>
<tr>
<td>
<<
</td>
<td colspan="5">
@currentMonth @firstDay.Year
</td>
<td>
>>
</td>
</tr>
</thead>
<tr>
<td>
Mon
</td>
<td>
Tue
</td>
<td>
Wed
</td>
<td>
Thu
</td>
<td>
Fri
</td>
<td>
Sat
</td>
<td>
Sun
</td>
</tr>
Alrighty, so we’ve got our calendar page header, showing both month and year, we’ve got days of the week columns, so let’s move to rendering dates
<tr>
<!-- filling up space of previous month -->
@for (int a = 1; a < dayOfWeekFirst; a++)
{
@:<td></td>
}
<!-- filling up space of current month -->
@for (int i = 1; i <= daysInCurrentMonth; i++)
{
DateTime renderedDay = new DateTime(firstDay.Year, firstDay.Month, i);
// if Sunday
if (renderedDay.DayOfWeek == DayOfWeek.Sunday)
{
@:<td class="calendar-holiday">@i</td></tr><tr>
}
// if Saturday
else if (renderedDay.DayOfWeek == DayOfWeek.Saturday)
{
@:<td class="calendar-holiday">@i</td>
}
// if normal day
else
{
@:<td>@i</td>
}
}
<!-- filling up space of next month -->
@for (int a = 1; a <= 7-dayOfWeekLast; a++)
{
@:<td></td>
}
</tr>
</table>
And that’s it. Now just add
@Html.Partial("_ReservationCalendar")
to render our partial view / user control on any page you want. There rest is really up to you, you can pass a collection of dates to be marked on your calendar from ViewModel and just place another if else for renderedDay variable. You gain control over what’s displayed and how ( do CSS magic ! ), you can add links, pop ups and whatever else you need.
That’s nothing really complex or sophisticated but maybe someone will find it useful
Wersja polska
Jeden z moich klientów proprosił mnie o stworzenie systemu rezerwacji rzeczy różnych
Wszystko szło gładko dopóki nie powiedział, że najlepiej by było gdyby dostępność określonej rzeczy była przestawiona na kalendarzu. W sumie nic trudnego ale w wymaganiach pojawiły się między innymi : możliwość określenia dat dostępności, terminy, które zostały wstępnie zarezerwowane ale jeszcze nie są opłacone oraz terminy zapłacone – każdy miał być wyróżniony w inny sposób. Rozpocząłem przeszukiwanie sieci ale niestety, okazało się że istniejące kontrolki i pluginy albo nie oferują tego czego mi potrzeba, albo ich intergracja i przerabianie zajmie mi więcej czasu niż napisanie podstawy kalendarza w taki sposób abym mógł go łatwo rozbudować.
Zacząłem od określenia danych których PartialView będzie potrzebował aby “wyrenderować” mi wymarzony kalendarz.
Ostatecznie określiłem następujące zmienne
- miesiąc i rok
- ilość dni w wybranym miesiącu
- dzień tygodnia dla pierwszego i ostatniego dnia miesiąca
W aplikacji te dane pewnie będziesz chciał przekazać przez ViewModel. Aby uprościć sobie życie wrzuciłem wszystko w jeden plik cshtml (ah tak, używamy MVC3 i Razora ). Dodajmy więc do projektu, w ścieżce /View/Shared plik _ReservationCalendar.cshtml. Teraz jego zawartość
(listing kodu #1)
Kiedy określiliśmy już zmienne pora stworzyć nagłówek tabeli naszego kalendarza
(listing kodu #2)
Skoro mamy i to przejdźmy do części właściwej czyli pętli, która wygeneruje nam kolejne kratki kalendarza. Dla każdej iteracji stworzymy obiek DateTime dzięki któremu dowiemy się jakim dniem tygodnia jest dany dzień ( lub sprawdzimy czy nie jest zarezerwowany lub cokolwiek innego potrzebujesz ). Rozpoczynając i kończąc strukturę kalendarza uzupełnimy sobie brakujące kratki na podstawie różnicy pomiędzy ilością dni w pełnym tygodniu a numerem dnia pierwszego (na początku) lub ostatniego (na końcu) danego miesiąca.
(listing kodu #3)
I koniec, teraz wystarczy że dodamy następujący wpis na stronie, na której kalendarz ma się pojawić :
(listing kodu #4)
Ten bardzo prosty kawałek kodu pozwala zbudować elastyczny kalendarz, który łatwo zintegrujesz ze swoją stroną w ASP.NET MVC3. Aby rozbudować jego możliwości przede wszystkim trzeba stworzyć odpowiedni ViewModel za pomocą którego przekażesz kolekcję dat do oznaczenia (bądź wykluczenia), wybrany do wyświetlenia miesiąc i rok itd itd. Zysujesz też pełną kontrolę nad wyglądem i zachowaniem kalendarza, wykorzystaniem Ajax – co dla mnie okazało się szybsze i wydajniejsze … ale może pobłądziłem ?
Hello! I like your calendar very much!! Any idea of haw to show in the dayOfWeekFirst the last days of the previous month and in the 7 – dayOfWeekLast the first days of the next month???? Thak you!!!!
hey, sorry for the late response, have solved your riddle
?