iEntry 10th Anniversary CSS Snippets JavaScript Snippets

 
 





Advance Calendar

In the last tutorial, we created a basic calendar that would return only the current month. This is great if you want to have just one month for the user to look at, but what if the user wants to look at other months? What if they want to check a date that your site may have spoken about? That is where this calendar comes into effect. We are going to create a calendar which will allow the user to go forward and backwards for each month.

The first thing we have to do is think of a way to create an interface that will be easy to use and not need explanation. The best designs for an interface are very simple and clean. The interface we are going to create will have two greater than or less than signs beside the month name. This should allow the user to know just by looking at the calendar that these signs allow them to go forward or backwards one month. If the use still does not understand this, we will add title and alt tags that will say previous and next month when the signs are hovered over. The rest of the calendar will have a table layout, just like the last calendar tutorial.

So now that we have the layout for our interface we need to start thinking of how to actually code this interface. We know that we are going to have a table, we can integrate the next and previous buttons into the table, along with the month that is being displayed into the "title" of the table with the th tags. So the calendar table should look like the following so far.

<table>
 <tr>
  <th><<</th>
  <th>June 2008</th>
  &tl;th>>></th>
 </tr>
</table>

Since we need to make the cells with the greater than and less than signs change the month we need to add that into the code. To allow this action to take place we are going to use JavaScript, so we don't really have to have an anchor tag that links to anything. Instead we can create a span tag and use the onclick JavaScript event to seem like an anchor tag. Before we do this, we have to create a JavaScript variable that we are going to change and we need to create a function to pass the changed variable too. Let's call our Javascript variable mydate and the value assigned to it will be "new Date()". We will also create a function named calendar that will check to see if the user has clicked to change the month, and if it has not then set the month to the current month. Since we are creating a variable to get the current date, we will also create two variables that will get the current day and the current year. These variables will be named day and year based on what information they will hold. The first example below sets creates the mydate variable in JavaScript, the second is the HTML code above with the new span tags which will allow the user to move forward or backwards one month.

<script type="text/javascript">
 var mydate = new Date();
 var day = mydate.getDate();
 var year = mydate.getFullYear();

function calendar(month){
 if (month){
  mynewdate = new Date(month + day + year);
 }else{
  mynewdate = new Date();
 } 
}
</script>

<table>
 <tr>
  <th><span onclick='calendar(mydate.setMonth(mydate.getMonth()-1))' title='Previous Month' alt='Previous Month'><<</span></th>
  <th>June 2008</th>
  <th>>span onclick='calendar(mydate.setMonth(mydate.getMonth()+1))' title='Previous Month' alt='Previous Month'> >></span></th>
 </tr>
</table>

The code that is passed to calendar may look confusing at first but lets take a more in depth look at the code.

calendar(mydate.setMonth(mydate.getMonth()-1))

So what exactly is this code doing? To brake it down further let's look at some of the parts of the code that we understand.

mydate.setMonth()

We know that this part of the code sets the month for the variable mydate. We also know that mydate is a variable that deals with date and has the value of new Date(). So with this code we are setting the month. Now what are we setting the month to? Since we know that we have to pass a number value to setMonth() function in order to set the month. That is where the next part of the code comes into play.

mydate.getMonth()-1

Before we deal with the negative one, we know that the first part of the code gets the month from the variable mydate. By adding the -1 to the code we are taking away one from that number. So this is basically getting the current month's number according to JavaScript and subtracting one from it. This gives us the previous month's number. We do the same thing with to get the next month's JavaScript value, except we add one instead of subtracting it.

Now that we have know what the HTML part of the code does, lets look a little deeper into the JavaScript code that we have so far, more important the calendar function that we have created.

function calendar(month){
 if (month){
  mynewdate = new Date(month + day + year);
 }else{
  mynewdate = new Date();
 } 
}

The calendar function only has one purpose for right now. This if statement is checking to verify if a value is set to month, since month is the name of the variable that can be passed to this function. If month has a value, then the statement uses this value to create a new date variable that sets the date to the month value that was passed to it along with the day and year values that we created as a global variable before the calendar function. If nothing is passed to the calendar function then we create a variable and set it's value to the current date value.

The next thing we should do is create the table that will display the calendar. First, we need to find out what day of the week the first day of the month is on. To do this we will need to use the JavaScript function getDay(). We can not use this on any of the date variables we already have, because mydate and mynewdate are both set to use the current day of the month. So in order to find out what the first day of the month starts on we will use mynewdate to create a temporary date that we can use to find out this information.

 var tempdate = new Date((mynewdate.getMonth()+1) +' 1 ,'+year); 

The above code will set allow use to set the temporary date to the first day of the current month and year. This seems great but what if the user advances to the next year? We now need to create some code to make for sure that if the user advances to the next year, then the code will know that is no longer the same year. To do this we need to get the year from mynewdate. Once we get the year, we can then pass that value on to the tempdate variable. Since we are creating a new variable, called tempyear, we will also need to change the year variable in tempdate to the new tempyear variable. We are doing this because we want to keep year the same value as it's global value in the entire script. Since we have to create this temporary date when ever the month is created or changed, we will add this to the calendar function. Here is how the updated calendar function looks.

function calendar(month){
 if (month){
  mynewdate = new Date(month + day + year);
 }else{
  mynewdate = new Date();
 } 

 var tempyear = mynewdate.getFullYear();
 var tempdate = new Date((mynewdate.getMonth()+1) +' 1 ,'+tempyear);
}

Now that we have temporary date that is set to the first of the month, we can find out what day of the week the first of the month falls on. As stated above we will use the getDay() function to do so. Here is that code.

var startday = tempdate.getDay()

Now that we have this information we know where the first day of the week the month starts on. We can now pad the calendar with extra cells to position the first day of the month correctly, but why not have the last days of the previous month show up grayed out? This is an advance calendar anyways. In order to do this we have to know a few things. First is what was the previous month, and how many days were in that month. This seems simple enough right, just take one away from the current month that is displayed. Seems simple at first, but then we have to take in account for February it does not have a set number of days each year. To figure this out we need to use some math. To determine if the year is a leap year we just divide by 4. We also know that if the year ends with two zeros (ie 1900, 2000) we have to divide by 400. If the number is divisible with no reminders then the current year is a leap year. To check for reminders, we can use the modulus (%) math function in JavaScript. We now need to check this with the tempyear variable. We are using the temp year variable because it is designed to show what year the user is currently on. Here is that math function in JavaScript code and setting a variable (totalFeb) with the correct amount of days.

 if ((tempdate.getFullYear%100!=0) && (tempdate.getFullYear%4==0) || (tempdate.getFullYear%400==0)){
  var totalFeb = 29;
 }else{
  var totalFeb = 28;
 }

To determine what year the user is currently in we use the tempyear since this will change when the user changes years. Now we can create an array for the numbers of days that the previous month had using the totalFeb variable.

var totalDays = ["31", ""+totalFeb+"","31","30","31","30","31","31","30","31","30","31"]

Now we need to find the previous month, and then use that to get the amount of days in the month. To get the previous month all we have to do is subtract one from the month that is currently being used. The following code will give us that information.

var prevMonth = (mynewdate.getMonth()-1)

Since we have the previous month, we can then pull the correct number of days from the array, just by using the following.

var prevMonthdays = totalDays[prevMonth];

Everything seems to be done, or so it seems. In JavaScript, an array starts at zero, so does the month values. Thus, January is also zero in Javascript. If the month on the calendar is January that means that when using the above code we would be taking one from zero and if we try to plug that into our array we will not find a value. Since an array can not have a negative key entry we need to create a small if statement to get around this issue.

if (prevMonth < 0){
 var prevMonthreverse = 31 - startday +1;
}else{
var prevMonthreverse = prevMonthdays - startday + 1;
}

The if statement is very simple, but it does two things. First it checks to see if prevMonth is less than zero. If so that would mean the current month is January, and the previous month was December of the previous year. This allows us to get around the bug we had where the array with the number of days in each month would have caused an issue. The other thing this if statement does is set the value for prevMonthreverse. What does that variable do? This variable takes the value assigned to startday (or the value of the weekday of the week that the first day of the month falls on) from the total number of days in the previous month then adds one. If we did not add the one in the equation, then the days will we off by one. In other words the months would display the day one higher the what it actually should. This variable will be used as a counter to fill the grayed numbers for the previous month. Now that we have how many cells we need to pad before the starting to count the days of the previous month, and a value to put in these cells we can create a while loop to create this section of the table.

Let's now create the loop. First thing we need to do is create a variable to be used as a counter, then we need to repeat the loop while this counter is less than the day of the week that the month starts on. We will also need to increase both the counter and the variable preMonthreverse by one each time the loop is repeated. Along with this, we have to output the value of the preMonthreverse value wrapped in HTML table tags. We also have to enclose this loop in a if statement. Because if the month starts on a Sunday, we will not need to have any cell padding.

Before we do this, we need to put the part of the table header we created earlier in the tutorial into a variable. That way the entire table is within on variable we can use later on. We are going to name this variable calendarbuild. Here is the code for both of those changes.


var calendarbuild = "<table class='calendar'>";
calendarbuild += "<tr class='currentmonth'><th class='month'><span onclick='calendar(mydate.setMonth(mydate.getMonth()-1))' title='Previous Month' alt='Previous Month'><< </span></th>";
calendarbuild += "<th class='calendar_month' colspan='5'>"+monthNames[mynewmonth]+" "+mynewyear+"</th>";
calendarbuild += "<th><span onclick='calendar(mydate.setMonth(mydate.getMonth()+1))'> >></span></th></tr>";
calendarbuild += "<tr class='startdays'>  <td>Sun</td>  <td>Mon</td> <td>Tues</td> <td>Wed</td> <td>Thur</td> <td>Fri</td> <td>Sat</td> </tr>";
calendarbuild += "<tr>";

if (startday != 0){
 while (startday > 0){
  calendarbuild += ""+prevMonthreverse+" ";
  prevMonthreverse++;
  startday --;
 }
}

At this point in the code, we have the start of the calendar, with the table cells from the previous month populated and have the ability to change what month the user wants to look at. We now need to fill in the rest of the calendar. So let's do that right now.

Like before we just need to create a counter and set this to one to create a loop. We will need to have this number count up until it is equal to the number of days in the month. To get the number of days in the month we can use the array we created before. One of the other things we will need to do is check to see what day of the week the loop is at, and if it is Saturday, then create a new row for the table. To see what day of the week we are currently at in the loop, we will need to create a second variable. This will be the same as startday variable that we created for the previous loop. We can not use the startday value as it is right now in the code, because we have changed the value from the original value in the last loop. To get around this we can do one of two things with the new variable. We can either create the variable before the loop that fills in the previous month days, and set the variable to equal the value of startday, or we can just create the variable just like we did startday. We will do the later in this tutorial.


var d = 1
var w = tempdate.getDay()

while (d <=totalDays[mynewdate.getMonth()]){
 if (w > 6){
  w = 0;
  calendarbuild += "</tr><tr>";
 }
 
 if (d == day){
  calendarbuild += "<td class='currentday'>"+d+"</td>";
 }else{
  calendarbuild += "<td class='currentmonth'>"+d+"</td>";
 }

 d++;
 w++;
}

So we know what the code does, but let's look at both of the if statements within the loop, starting with the first statement.

 if (w > 6){
  w = 0;
  calendarbuild += "</tr><tr>";
 }

This part of the loop will create the new row if the loop is on Saturday. Since we know that JavaScript numbers each day of the week from zero to six starting with Sunday, we can insert a new row once the day gets to Saturday. The variable w was given the value of the whatever day of the week the first day of the month started. This can be any number between zero and six. Since we don't want this number to go over six, we have to have the loop check to see if w is less than that. If it does go over six, we reset the value back to zero, then insert a closing table row element and an opening row element. Now let's look at the second statement in this loop.

 if (d == day){
  calendarbuild += "<td class='currentday'>"+d+"</td>";
 }else{
  calendarbuild += "<td class='currentmonth'>"+d+"</td>";
 }

The second loop will fill in the reset of the month. You don't have to have this loop but we have it for on purpose. When we apply a style sheet to the month we want to make the current day stand out. That is what the second if statement does. It checks to see if the counter is equal to the current value of the global variable day. We set day's value to the current day of the month outside of the calendar loop. If the not we then apply a different style to the cell. Following this statement, we increase both variables w and d, by one.

We also need to fill in the rest of the calendar by adding the next month's days until the calendar is filled. To do this we are going to create a variable named nextMonth, and well set this value to one. This code is just like the code we used to fill the calendar with the previous month's dates. The only difference is this will only loop until the end of the week. To make for sure we are creating cells from where the last day of the current month left off at, we will also use the w variable, and tell the loop to stop when w equals six.

var nextMonth = 1;
while (w <= 6){
 calendarbuild += "<td>"+nextMonth+"</td>";
 nextMonth++;
 w ++;
}

The only thing to do now is to close the table we created, and tell the JavaScript where we want to display the calendar. Those are shown below.

 calendarbuild += "";

 document.getElementById('calendar').innerHTML = calendarbuild;

To display the calendar in the HTML body we will only need to use this code.

<div id="calendar"> <script> calendar();</script></div>

To see an example of this code you can here. In the example we have added style sheets to allow the calendar to have a cleaner look applied to it. We have also added some extra JavaScript to highlight the current day that the user has hovered over. To create the same effect read our tutorial titled Table Row Highlight. We use the same effect but apply it to each cell instead of the entire row.

*Note this script only works in Firefox. Opera will give the wrong days for the month, and IE does not wrap the table properly.