0

I am building a simple JavaScript calendar. So far I'm able to navigate through the next and previous month and year. I'm having an issue trying to populate the days of the month. Each time I click one of the navigation arrows, it keeps adding 1's. I know I already asked about this earlier, but I'm so close to having it resolved and don't understand why I keep getting 1's.

$(document).ready(function(){

var d = new Date();

function myCalendar() {

var month = d.getUTCMonth();
var day = d.getUTCDate();
var year = d.getUTCFullYear();
var nextMonth = month + 1;
var preMonth = month - 1;
var febDays = '';
var html = '';
var counter = 1;


// Displays the current month in Strings and the actual year 
switch(month) {
	case 0: $('.month-year').append('<h3> ' + 'January' + ' ' +  year + ' </h3>' ); break;
	case 1: $('.month-year').append('<h3> ' + 'February' + ' ' + year + ' </h3>' ); break;
	case 2: $('.month-year').append('<h3> ' + 'March' + ' ' + year + ' </h3>' ); break;
	case 3: $('.month-year').append('<h3> ' + 'April' + ' ' + year + ' </h3>' ); break;
	case 4: $('.month-year').append('<h3> ' + 'May' + ' ' + year + ' </h3>' ); break;
	case 5: $('.month-year').append('<h3> ' + 'June' + ' ' + year + ' </h3>' ); break;
	case 6: $('.month-year').append('<h3> ' + 'July' + ' ' + year + ' </h3>' ); break;
	case 7: $('.month-year').append('<h3> ' + 'August' + ' ' + year + ' </h3>' ); break;
	case 8: $('.month-year').append('<h3> ' + 'September' + ' ' + year + ' </h3>' ); break;
	case 9: $('.month-year').append('<h3> ' + 'October' + ' ' + year + ' </h3>' ); break;
	case 10: $('.month-year').append('<h3> ' + 'November' + ' ' + year + ' </h3>' ); break;
	case 11: $('.month-year').append('<h3> ' + 'December' + ' ' + year + ' </h3>' ); break;
	default:
	break;
}

//Getting February Days Including The Leap Year
if (month == 1) {
  if ((year % 100!=0) && (year% 4==0) || (year%400 == 0 )) {
    febDays = 29;
  } else {
    febDays = 28;
  }
}

// Getting The Months and Days of the Week
var weekDayName = ["SUN", "MON", "TUES", "WED", "THURS", "FRI"];
var daysOfMonth = ["31", " " + febDays + " " ,"31", "30", "31", "30", "31", "31", "30", "31", "30", "31" ];


// Getting The Previous Month and the Next Month including the day of the week

var nextDay = nextMonth + ' 1 ,';
var weekDays = nextDay.day;
var weekDays2 = weekDays;
var numberDays = daysOfMonth;


// For the Previous Month
while (weekDays <= 0) {
  $('td').addClass('prevMonth').append(html);

// For the Next Loop
  weekDays--;
}

//To build the calendar body
while (counter <= numberDays) {

  //Staring a New Line
  if (weekDays2 > 6) {
      weekDays2 = 0;
      $('tr').append(html);
  }
}

// To see if Counter is the Current Day
// The current day is colored in

if(counter == day) {
  $('td').addClass('today').append( html + counter);

} else {
  $('td').addClass('currentMonth').append(html + counter);
}

weekDays2++;
counter++;

};

myCalendar();
//Navigation Buttons
$('.prev-month').click(function(){
	$('.month-year').empty();
	d.setUTCMonth(d.getUTCMonth() - 1);
	myCalendar();	
});

$('.next-month').click(function(){
	$('.month-year').empty();
	d.setUTCMonth(d.getUTCMonth() + 1);
	myCalendar();
});

});
* {
	margin: 0;
	padding: 0;
}
.container {
	margin-top: 80px;
}
th {
	height: 30px;
	text-align: center;
	font-weight: 700;
}
td {
	height: 100px;
}
.today {
	background-color: gray;
}
th:nth-of-type(7), td:nth-of-type(7) {
	font-weight: bold;
}
th:nth-of-type(1), td:nth-of-type(1) {
	font-weight: bold;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<body>
   <div class="container">
      <i class="prev-month fa fa-chevron-left fa-3x"></i> <i class="next-month fa fa-chevron-right fa-3x"></i>
      <br>
      <div class="month-year text-center">
         <h3></h3>
      </div>
      <table class="table table-bordered">
         <tr>
            <th>S</th>
            <th>M</th>
            <th>T</th>
            <th>W</th>
            <th>T</th>
            <th>F</th>
            <th>S</th>
         </tr>
         <tr>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
         </tr>
         <tr>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
         </tr>
         <tr>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
         </tr>
         <tr>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
         </tr>
         <tr>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
         </tr>
         <tr>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
         </tr>
      </table>
   </div>
</body>

Here is my fiddle https://jsfiddle.net/o6fap41z/7/

7
  • 1
    Note that neither of your while loop conditions is true, but if they were true you'd have infinite loops. Anyway, is the desired output to have 1, 2, 3, 4, etc. to fill up the month? Commented Apr 10, 2017 at 7:12
  • Yes. They need to be filled with the dates of the current month. Commented Apr 10, 2017 at 7:19
  • @MichaelStokes, i am working on this, and have done > 50% of it. do you want me to post it here? Commented Apr 10, 2017 at 12:11
  • Go ahead and post it Commented Apr 10, 2017 at 12:34
  • @MichaelStokes, i've posted it as answer. actually i messed up a little on the algorithm and need some more time to work on it. Commented Apr 10, 2017 at 13:59

4 Answers 4

2

I have worked on this and have created a working calendar after lots of tweaks and debugging.

Check the below working snippet, and tell me if it was helpful.

	function myCalendar(curr_month = "curr") {
  var tbody_html = "";
  var td_class = "";
  var weekday_count = 1;
  var tr_count = 1;
   	  var td_count = 1;
  var offset_td = 0;
  var counter = 1;
  var month = master_data.months[curr_month];
  var start_of_curr = master_data.day_start[curr_month];
		if(curr_month!=="curr"){
			if(master_data.months[curr_month]===11 && curr_month==="prev"){
				year--;
			}
			if(master_data.months[curr_month]===0 && curr_month==="next"){
				year++;
			}
		}
		
		  // Displays the current month in Strings and the actual year 
		  $('.month-year').html("<h3>"+months_full[month]+" "+year+"</h3>");

		  //To build the calendar body
		  while (counter <= daysOfMonth[month]) {
		  	if(weekday_count === 8){
		  		tbody_html += "</tr>";
		  		weekday_count = 1;
		  	}
		  	if(weekday_count === 1){
		  		tbody_html += "<tr>";
		  		tr_count++;
		  	}
	  	// prepend blank tds
		  	while(offset_td < start_of_curr){
		  		tbody_html += "<td class='empty'></td>";
		  		offset_td++;
		  		weekday_count++;
		  		td_count++;
		  	}
		  	if(month === d.getUTCMonth() && year === d.getUTCFullYear()){
		  		if(counter === date){
		  			td_class = "today";
		  		} else {
		  			td_class = "currentMonth";
		  		}
		  	}
		  	tbody_html += "<td class='"+td_class+"'>"+counter+"</td>";
		  	counter++;
		  	weekday_count++;
		  	td_count++;
		  }
	  // append blank tds
		  while((td_count-1) < (tr_count-1)*7){
		  	tbody_html += "<td class='empty'></td>";
		  	td_count++;
		  }
		  $('#calendar_tbody').html(tbody_html);
	  // setting master_data.months
		  master_data.months.curr = month;
		  master_data.months.prev = month === 0 ? 11 : month - 1;
		  master_data.months.next = month === 11 ? 0 : month + 1;
		  debug && console.log("prev "+master_data.months.prev+" -> "+start_of_curr+" - "+daysOfMonth[master_data.months.prev]+"%7 = "+(start_of_curr - daysOfMonth[master_data.months.prev]%7));
	  // setting master_data.day_start
		  master_data.day_start.curr = start_of_curr;
		  var temp_prev_som = start_of_curr - daysOfMonth[master_data.months.prev]%7;
		  if(temp_prev_som < 0){
		  	temp_prev_som = 7 + temp_prev_som;
		  }
		  master_data.day_start.prev = temp_prev_som;
		  master_data.day_start.next = weekday_count === 8 ? 0 : weekday_count-1;
		  //return prev_next;
		  if(debug){
		  	console.log("    P   C   N   ");
		  	console.log(" m ", master_data.months.prev, " ", master_data.months.curr, " ", master_data.months.next);
		  	console.log(" d ", master_data.day_start.prev, " ", master_data.day_start.curr, " ", master_data.day_start.next);
		  }
		}
		var d = new Date();
		var year = d.getUTCFullYear();
		var day = d.getUTCDay();
		var date = d.getUTCDate();
		var month = d.getUTCMonth();
		// our global object
		var master_data = {
			day_start: {
				prev: 0, curr: day - (date%7 - 1) + 7, next: 0
			},
			months: {
				prev: month-1, curr: month, next: month+1
			}
		};
		//Getting February Days Including The Leap Year
		if ((year % 100!=0) && (year% 4==0) || (year%400 == 0 )) {
			var febDays = 29;
		} else {
			var febDays = 28;
		}
		// Getting The Months and Days of the Week
		var daysOfMonth = [31, febDays, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
		var months_full = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];

		var debug = false;
		$(document).ready(function(){
			console.clear();
			var d = new Date();
			myCalendar();
			var main_obj = master_data;
		  //Navigation Buttons
		  $('.prev-month').click(function(){
		  	myCalendar("prev");	
		  });

		  $('.next-month').click(function(){
		  	myCalendar("next");
		  });
		});
	
* {
			margin: 0;
			padding: 0;
		}
		.calendar_header{
			position: relative;
		}
		.prev-month, .next-month{
		    cursor: pointer;
		    position: absolute;
		    top: 1px;
		    background: #fff;
		    width: 50px;
		    height: 54px;
		    padding: 8px 0 8px 10px;
		}
		.prev-month{ left: 1px; }
		.next-month{ right: 1px; }
		.month-year h3{
			font-size: 40px;
			margin-top: 10px;
			border: 1px solid #ddd;
		    margin-bottom: 0;
		    padding: 5px 0;
		    background: #eee;
		}
		.currentMonth{background: rgba(0,0,0,0.04);}
		.container {
			margin-top: 10px;
		}

		th {
			background: #faffe0;
			border-bottom: 4px double #ddd !important;
			font-size: 20px;
			height: 30px;
			text-align: center;
			font-weight: 700;
		}

		td {
			font-size: 20px;
			background: rgba(0,0,0,0.02);
			height: 100px;
		}
		td.empty{background: #fff;}

		.today {
			font-weight: bold;
			color: #fff;
			background-color: gray;
		}

		th:nth-of-type(7), td:nth-of-type(7) {
			font-weight: bold;
		}

		th:nth-of-type(1), td:nth-of-type(1) {
			font-weight: bold;
		}
        .snippet-code .snippet-result .snippet-result-code{height:725px;}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
		<div class="calendar_header">
			<i class="prev-month fa fa-chevron-left fa-3x"></i>
			<i class="next-month fa fa-chevron-right fa-3x"></i>
			<div class="month-year text-center"></div>
		</div>
		<table class="table table-bordered">
			<thead>
				<tr>
					<th>S</th>
					<th>M</th>
					<th>T</th>
					<th>W</th>
					<th>T</th>
					<th>F</th>
					<th>S</th>
				</tr>
			</thead>
			<tbody id="calendar_tbody"></tbody>
		</table>
	</div>

Here is my fiddle link, if someone needs it.

Sign up to request clarification or add additional context in comments.

4 Comments

@MichaelStokes, check the answer. tell me if it was helpful.
Everything is working the way I want it but the entire code is different. I was a bit confused with the algorithms but I understand what they are doing. Thanks for everything.
I want to know how you came up with the solution? Your JavaScript skills are amazing and I would never come up with those kind of algorithms.
i took just 2 things to build up the logic: 1st- num of days in a month and 2nd- start day of the month. then calculated the start day of prev or next month based on start of current month and the num of days in next or prev month. i used counters wherever it was required. but i guess there must be a better solution than this! anyway thanks for the compliment.. happy learning :)
2

This is an older question, so you may have found the solution. I just wanted to add a comment in the event others come across this question or if you're still working on this.

You asked why you keep getting 1s. The cause of this is due to the following code:

if (counter == day) {
  $('td').addClass('today').append(html + counter);
} else {
  $('td').addClass('currentMonth').append(html + counter);
}

Or, in your case, specifically the else block. So, what's going on?

Well, for what's going on, we need to look at jQuery. One of jQuery's best feature is implicit iteration. That is, if you do this:

$('div').addClass('cool--div');

jQuery will apply the class cool-div to ALL divs selected. You can think of this as implicitly looping over all the elements jQuery found and then applying our class. The implicit iteration of td in the else block above is the cause of your 1s (coupled with the non-working while loops, that don't increase the count).

Here's a fiddle demonstrating implicit iteration: https://jsfiddle.net/o6fap41z/22/

As for a quick working solution, here's a Fiddle I threw together: https://jsfiddle.net/o6fap41z/28/

And the code snippet:

var CURRENT_DATE = new Date();
var d = new Date();

var content = 'January February March April May June July August September October November December'.split(' ');
var weekDayName = 'SUN MON TUES WED THURS FRI'.split(' ');
var daysOfMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

// Returns the day of week which month starts (eg 0 for Sunday, 1 for Monday, etc.)
function getCalendarStart(dayOfWeek, currentDate) {
  var date = currentDate - 1;
  var startOffset = (date % 7) - dayOfWeek;
  if (startOffset > 0) {
    startOffset -= 7;
  }
  return Math.abs(startOffset);
}

// Render Calendar
function renderCalendar(startDay, totalDays, currentDate) {
  var currentRow = 1;
  var currentDay = startDay;
  var $table = $('table');
  var $week = getCalendarRow();
  var $day;
  var i = 1;

  for (; i <= totalDays; i++) {
    $day = $week.find('td').eq(currentDay);
    $day.text(i);
    if (i === currentDate) {
      $day.addClass('today');
    }

    // +1 next day until Saturday (6), then reset to Sunday (0)
    currentDay = ++currentDay % 7;

    // Generate new row when day is Saturday, but only if there are
    // additional days to render
    if (currentDay === 0 && (i + 1 <= totalDays)) {
      $week = getCalendarRow();
      currentRow++;
    }
  }
}

// Clear generated calendar
function clearCalendar() {
  var $trs = $('tr').not(':eq(0)');
  $trs.remove();
  $('.month-year').empty();
}

// Generates table row used when rendering Calendar
function getCalendarRow() {
  var $table = $('table');
  var $tr = $('<tr/>');
  for (var i = 0, len = 7; i < len; i++) {
    $tr.append($('<td/>'));
  }
  $table.append($tr);
  return $tr;
}

function myCalendar() {
  var month = d.getUTCMonth();
  var day = d.getUTCDay();
  var year = d.getUTCFullYear();
  var date = d.getUTCDate();
  var totalDaysOfMonth = daysOfMonth[month];
  var counter = 1;

  var $h3 = $('<h3>');

  $h3.text(content[month] + ' ' + year);
  $h3.appendTo('.month-year');

  var dateToHighlight = 0;

  // Determine if Month && Year are current for Date Highlight
  if (CURRENT_DATE.getUTCMonth() === month && CURRENT_DATE.getUTCFullYear() === year) {
    dateToHighlight = date;
  }

  //Getting February Days Including The Leap Year
  if (month === 1) {
    if ((year % 100 !== 0) && (year % 4 === 0) || (year % 400 === 0)) {
      totalDaysOfMonth = 29;
    }
  }

  // Get Start Day
  renderCalendar(getCalendarStart(day, date), totalDaysOfMonth, dateToHighlight);
};

function navigationHandler(dir) {
  d.setUTCMonth(d.getUTCMonth() + dir);
  clearCalendar();
  myCalendar();
}

$(document).ready(function() {
  // Bind Events
  $('.prev-month').click(function() {
    navigationHandler(-1);
  });
  $('.next-month').click(function() {
    navigationHandler(1);
  });
  // Generate Calendar
  myCalendar();
});
* {
  margin: 0;
  padding: 0;
}

.container {
  margin-top: 80px;
}

th {
  height: 30px;
  text-align: center;
  font-weight: 700;
}

td {
  height: 100px;
}

.today {
  background-color: gray;
}

th:nth-of-type(7),
td:nth-of-type(7) {
  font-weight: bold;
}

th:nth-of-type(1),
td:nth-of-type(1) {
  font-weight: bold;
}
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div class="container">
  <i class="prev-month fa fa-chevron-left fa-3x"></i> <i class="next-month fa fa-chevron-right fa-3x"></i>
  <br>
  <div class="month-year text-center">
    <h3></h3></div>
  <table class="table table-bordered">
    <tr>
      <th>S</th>
      <th>M</th>
      <th>T</th>
      <th>W</th>
      <th>T</th>
      <th>F</th>
      <th>S</th>
    </tr>
  </table>
</div>

Hope this helps and happy learnings!

1 Comment

This can be very useful the next time I build a calendar. Thanks for providing me this!
1

Here is my code using Plain Javascript only

class Calendar {
constructor() {
    this.months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    this.days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
}
create(year, month) {
    const table = document.createElement('table');
    const tBody = document.createElement('tbody');
    const firstDay = (new Date(year, month)).getDay();
    const getNoOfDays = this.getDaysInMonth(year, month);
    let date = 1;
    const heading = this.showMonthYearTitle(year, month);
    const div = document.createElement('div');
    div.appendChild(heading);
    this.createDays(table);
    for(let j = 0; j < 6; j++) {
        const tr = document.createElement('tr');
        for(let i = 0, len = this.days.length; i < len ; i++) {
            const td = document.createElement('td');
            let textNode;
            if(j === 0 && i < firstDay) {
                textNode = document.createTextNode('');
            } else if(getNoOfDays >= date) {
                textNode = document.createTextNode(date);
                date++;
            }
            else break;
            td.appendChild(textNode);
            tr.appendChild(td);
        }
        tBody.appendChild(tr);
    }
    table.appendChild(tBody);
    div.appendChild(table);
    return div;
}
createDays(table) {
    const tHead = document.createElement('thead');
    const tr = document.createElement('tr');
    for(let i = 0, len = this.days.length; i < len ; i++) {
        const td = document.createElement('td');
        const textNode = document.createTextNode(this.days[i]);
        td.appendChild(textNode);
        tr.appendChild(td);
    }
    tHead.appendChild(tr);
    table.appendChild(tHead);
}
showFullYear(year) {
    for(let i = 0, len = this.months.length; i < len; i++) {
        const table = this.create(year, i);
        document.body.appendChild(table);
    }
}
getDaysInMonth(year, month) {return new Date(year, month + 1, 0).getDate();}
showMonthYearTitle(year, month) {
   const elem = document.createElement('div');
    elem.innerHTML = this.months[month] + ', ' + year;
    return elem;
}

}

var cal = new Calendar();
cal.showFullYear(2020);

class Calendar {
    constructor() {
        this.months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
        this.days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
    }
    create(year, month) {
        const table = document.createElement('table');
        const tBody = document.createElement('tbody');
        const firstDay = (new Date(year, month)).getDay();
        const getNoOfDays = this.getDaysInMonth(year, month);
        let date = 1;
        const heading = this.showMonthYearTitle(year, month);
        const div = document.createElement('div');
        div.appendChild(heading);
        this.createDays(table);
        for(let j = 0; j < 6; j++) {
            const tr = document.createElement('tr');
            for(let i = 0, len = this.days.length; i < len ; i++) {
                const td = document.createElement('td');
                let textNode;
                if(j === 0 && i < firstDay) {
                    textNode = document.createTextNode('');
                } else if(getNoOfDays >= date) {
                    textNode = document.createTextNode(date);
                    date++;
                }
                else break;
                td.appendChild(textNode);
                tr.appendChild(td);
            }
            tBody.appendChild(tr);
        }
        table.appendChild(tBody);
        div.appendChild(table);
        return div;
    }
    createDays(table) {
        const tHead = document.createElement('thead');
        const tr = document.createElement('tr');
        for(let i = 0, len = this.days.length; i < len ; i++) {
            const td = document.createElement('td');
            const textNode = document.createTextNode(this.days[i]);
            td.appendChild(textNode);
            tr.appendChild(td);
        }
        tHead.appendChild(tr);
        table.appendChild(tHead);
    }
    showFullYear(year) {
        for(let i = 0, len = this.months.length; i < len; i++) {
            const table = this.create(year, i);
            document.body.appendChild(table);
        }
    }
    getDaysInMonth(year, month) {return new Date(year, month + 1, 0).getDate();}
    showMonthYearTitle(year, month) {
       const elem = document.createElement('div');
        elem.innerHTML = this.months[month] + ', ' + year;
        return elem;
    }
}

var cal = new Calendar();
cal.showFullYear(2020);

Comments

0

replace .append with .html in below code

if (counter == day) {
      $('td').addClass('today').append(html + counter);
    } else {
      $('td').addClass('currentMonth').append(html + counter);
    }

i.e

if (counter == day) {
      $('td').addClass('today').html(html + counter);
    } else {
      $('td').addClass('currentMonth').html(html + counter);
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.