I'm still new in javascript and learning. I want to create a date picker using html and javascript. Below is what I have tried and it's working, so my question is "how can I do it better?" My idea is to create a custom tag in HTML and allow multiple of these tags. The javascript part will then handle the build and functionality of all the custom tags. Like I said it is working, I just want to get some feedback to help making it better.
I have done everything, The HTML and javascript and both are working. See below my code:
let currentDate = new Date();
let currentMonth = currentDate.getMonth();
let currentYear = currentDate.getFullYear();
let months = ["January", "February", "March", "April", "May", "June", "July","August", "September", "October","November", "December"];
let daysOfTheMonth = ["S","M","T","W","T","F","S"];
var datePickers = document.getElementsByTagName("datePicker");
class Calendar {
constructor(id,year, month) {
this.id = id,
this.year = year,
this.month = month,
this.header = months[this.month] + " " + this.year;
}
previous(calendarBody,calendarHeader,mainHeader){
this.year = (this.month === 0) ? this.year - 1 : this.year;
this.month = (this.month === 0) ? 11 : this.month - 1;
this.update(calendarBody,calendarHeader,mainHeader)
}
next(calendarBody,calendarHeader,mainHeader) {
this.year = (this.month === 11) ? this.year + 1 : this.year;
this.month = (this.month + 1) % 12;
this.update(calendarBody,calendarHeader,mainHeader)
}
selectDate(date){
let year = this.year;
let month = this.month;
let newDate = new Date(year, month, date)
const newMonth = newDate.toLocaleString('default', { month: 'short' });
var dayName = newDate.toString().split(' ')[0];
document.getElementById("topHeader_"+ this.id).innerHTML = dayName+", "+ newMonth + " "+ date
document.getElementById("input_"+ this.id).value = formatDate(newDate)
}
update(calendarBody,calendarHeader,mainHeader){
let month = currentDate.toLocaleString('default', { month: 'short' });
let dayName = currentDate.toString().split(' ')[0];
mainHeader.innerHTML = dayName+", "+ month + " " + currentDate.getDate();
calendarHeader.innerHTML = months[this.month] + " " + this.year;
calendarBody.innerHTML = "";
let firstDay = (new Date(this.year, this.month)).getDay();
let daysInMonth = 32 - new Date(this.year, this.month, 32).getDate();
let date = 1;
for (let i = 0; i < 6; i++) {
let row = document.createElement("tr");
for (let j = 0; j < 7; j++) {
if (i === 0 && j < firstDay) {
let cell = document.createElement("td");
cell.innerHTML = ""
row.appendChild(cell);
}
else if (date > daysInMonth) {
break;
}
else {
let vm = this;
let cell = document.createElement("td");
let button = document.createElement("button");
button.innerHTML = date;
cell.appendChild(button);
button.addEventListener('click',function(e){
vm.selectDate(e.target.innerHTML);
});
if (date === currentDate.getDate() && this.year === currentDate.getFullYear() && this.month === currentDate.getMonth()) {
cell.classList.add("today");
}
row.appendChild(cell);
date++;
}
}
calendarBody.appendChild(row);
}
}
createPicker(datePicker){
let vm = this;
let mainHeader = document.createElement("div");
mainHeader.setAttribute("id", "topHeader_"+ vm.id)
mainHeader.classList.add("topHeader");
mainHeader.innerHTML = vm.header;
let calendar = document.createElement("div");
calendar.setAttribute("id", "calendar_"+vm.id);
calendar.setAttribute("class", "calendar");
calendar.style.display = "none";
calendar.appendChild(mainHeader);
let input = document.createElement("input");
input.setAttribute("type", "text");
input.setAttribute("id", "input_"+ vm.id);
input.setAttribute("tagName", "input");
input.setAttribute("class", "datePickerInput");
input.setAttribute("calendar", "calendar_"+vm.id);
input.setAttribute("placeholder", "Select a date");
datePicker.appendChild(input);
let calendarHeaderContainer = document.createElement("div");
let prevButton = document.createElement("button");
prevButton.setAttribute("id", "prevButton_"+vm.id);
prevButton.innerHTML = "<";
let nextButton = document.createElement("button");
nextButton.setAttribute("id", "nextButton_"+vm.id);
nextButton.innerHTML = ">";
calendarHeaderContainer.appendChild(prevButton);
let calendarHeader = document.createElement("div");
calendarHeader.setAttribute("id", "calendar_header_"+vm.id);
calendarHeader.setAttribute("class", "calendar_header");
calendarHeader.innerHTML = vm.header;
calendarHeaderContainer.appendChild(calendarHeader);
calendarHeaderContainer.appendChild(nextButton);
let calendarTable = document.createElement("table");
calendarTable.setAttribute("id", "calendar_body_"+vm.id);
let calendarTableBody = calendarTable.createTBody();
let calendarTableHeader = calendarTable.createTHead();
calendarTableHeader.classList.add("daysOfTheMonth");
let row = document.createElement("tr");
for (let j = 0; j < daysOfTheMonth.length; j++) {
let cell = document.createElement("td");
cell.innerHTML = daysOfTheMonth[j];
row.appendChild(cell);
}
calendarTableHeader.appendChild(row);
this.update(calendarTableBody,calendarHeader,mainHeader)
calendar.appendChild(calendarHeaderContainer);
calendar.appendChild(calendarTable);
datePicker.appendChild(calendar);
input.addEventListener('click',function(e){
let calendar = document.getElementById(this.getAttribute("calendar"));
if(calendar.style.display === "none"){
calendar.style.display = "block"
}else{
calendar.style.display = "none"
}
});
nextButton.addEventListener('click',function(e){
vm.next(calendarTableBody,calendarHeader,mainHeader);
});
prevButton.addEventListener('click',function(e){
vm.previous(calendarTableBody,calendarHeader,mainHeader);
});
}
}
function formatDate(date) {
var d = new Date(date),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate(),
year = d.getFullYear();
if (month.length < 2) month = '0' + month;
if (day.length < 2) day = '0' + day;
return [year, month, day].join('-');
}
for ( var x = 0; x < datePickers.length; x++) {
var calendar = new Calendar(x, currentYear, currentMonth);
calendar.createPicker(datePickers[x])
}
.calendar {
width: 250px;
background: gainsboro;
border-radius: 5px;
}
.calendarHeaderContainer {
display: flex;
justify-content: space-between;
align-items: center;
}
.topHeader {
font-size: 20px;
background: #03A9F4;
padding: 10px;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
/*Button Reset*/
button {
background: none;
border: none;
}
<h1>Date Picker</h1>
<datePicker></datePicker>
One thing I do want to know is: I want to return the selected date for each picker and it also has to be by the id of the picker so you know what date goes where.
Thanks again, everyone.