0

I found this calendar code online, I wish to work on it and add a on click listener on each day and return the selected date but I can't find the for each of the days in the code hence I do not know how to add in the onclick listener.

Here is the code.

const date = new Date();

const renderCalendar = () => {
  date.setDate(1);

  const monthDays = document.querySelector(".days");

  const lastDay = new Date(
    date.getFullYear(),
    date.getMonth() + 1,
    0
  ).getDate(); 

  const prevLastDay = new Date(
    date.getFullYear(),
    date.getMonth(),
    0
  ).getDate(); 

  const firstDayIndex = date.getDay();

  const lastDayIndex = new Date(
    date.getFullYear(),
    date.getMonth() + 1,
    0
  ).getDay();

  const nextDays = 7 - lastDayIndex - 1;

  const months = [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December",
  ];


  document.querySelector(".date h1").innerHTML = months[date.getMonth()];
  document.querySelector(".date p").innerHTML = new Date().toDateString();

  let days = "";

  for (let x = firstDayIndex; x > 0; x--) {
    days += `<div class="prev-date">${prevLastDay - x + 1}</div>`;
    
  } 

  for (let i = 1; i <= lastDay; i++) {
      if (
        i >= new Date().getDate() &&
        date.getMonth() >= new Date().getMonth()
      ) {
        days += `<div class="green">${i}</div>`;
      } else {
        days += `<div class="red">${i}</div>`;
      }
    }
  

  monthDays.innerHTML = days;

};

document.querySelector(".prev").addEventListener("click", () => {
  date.setMonth(date.getMonth() - 1);
  renderCalendar();
});

document.querySelector(".next").addEventListener("click", () => {
  date.setMonth(date.getMonth() + 1);
  renderCalendar();
});
renderCalendar();
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: "Quicksand", sans-serif;
  }
  
  html {
    font-size: 62.5%;
  }
  
  .leaves {
    width: 100%;
    /* height: 100vh; */
    background-color: #12121f;
    color: #eee;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  
  .container {
    width: 100%;
    height: 100vh;
    background-color: #12121f;
    color: #eee;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  
  .calendar {
    width: 45rem;
    height: 52rem;
    background-color: #222227;
    box-shadow: 0 0.5rem 3rem rgba(0, 0, 0, 0.4);
  }
  
  .month {
    width: 100%;
    height: 12rem;
    background-color: #167e56;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 2rem;
    text-align: center;
    text-shadow: 0 0.3rem 0.5rem rgba(0, 0, 0, 0.5);
  }
  
  .month i {
    font-size: 2.5rem;
    cursor: pointer;
  }
  
  .month h1 {
    font-size: 3rem;
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.2rem;
    margin-bottom: 1rem;
  }
  
  .month p {
    font-size: 1.6rem;
  }
  
  .weekdays {
    width: 100%;
    height: 5rem;
    padding: 0 0.4rem;
    display: flex;
    align-items: center;
  }
  
  .weekdays div {
    font-size: 1.5rem;
    font-weight: 400;
    letter-spacing: 0.1rem;
    width: calc(44.2rem / 7);
    display: flex;
    justify-content: center;
    align-items: center;
    text-shadow: 0 0.3rem 0.5rem rgba(0, 0, 0, 0.5);
  }
  
  .days {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    padding: 0.2rem;
  }
  
  .days div {
    font-size: 1.4rem;
    margin: 0.3rem;
    width: calc(40.2rem / 7);
    height: 5rem;
    display: flex;
    justify-content: center;
    align-items: center;
    text-shadow: 0 0.3rem 0.5rem rgba(0, 0, 0, 0.5);
    transition: background-color 0.2s;
  }
  
  .days div:hover:not(.today) {
    background-color: #262626;
    border: 0.2rem solid #777;
    cursor: pointer;
  }
  
  .prev-date,
  .fcc-other-month { 
    visibility:hidden;
 }
  .next-date {
    opacity: 0.5;
  }
  
  .green {
    background-color: #167e56;
  }

  .red {
    background-color: red;
  }
<div class="leaves">
      <div class="calendar">
        <div class="month">
          <i class="fas fa-angle-left prev"></i>
          <div class="date">
            <h1></h1>
            <p></p>
          </div>
          <i class="fas fa-angle-right next"></i>
        </div>
        <div class="weekdays">
          <div>Sun</div>
          <div>Mon</div>
          <div>Tue</div>
          <div>Wed</div>
          <div>Thu</div>
          <div>Fri</div>
          <div>Sat</div>
        </div>
        <div class="days"></div>
      </div>
    </div>

I know that div class="green" is changing the color of today in green but if I want to change the color of days before today to red I added div class="red" but the next month not all of the days are in green. Next year everything will be red instead. Can I know what can I do to change the colors correctly

Cohen
  • 2,375
  • 3
  • 16
  • 35
Jin
  • 3
  • 2

1 Answers1

0

The loop you're looking for is this:

for (let i = 1; i <= lastDay; i++) {
if (i >= new Date().getDate() &&
    date.getMonth() >= new Date().getMonth()
  ) {
    days += `<div class="green">${i}</div>`;
  } else {
    days += `<div class="red">${i}</div>`;
  }
}

In the div itself, you'd have to add a class, let's say day, and then also add some type of data-* to it, let's say data-date whose value would be a date, e.g., 01-01. Then you can add a click listener to the class day and work with the event's currentTarget's dataset.

Your code would be something like this:

const date = new Date();

const renderCalendar = () => {
  date.setDate(1);

  const monthDays = document.querySelector(".days");

  const lastDay = new Date(
    date.getFullYear(),
    date.getMonth() + 1,
    0
  ).getDate(); 

  const prevLastDay = new Date(
    date.getFullYear(),
    date.getMonth(),
    0
  ).getDate(); 

  const firstDayIndex = date.getDay();

  const lastDayIndex = new Date(
    date.getFullYear(),
    date.getMonth() + 1,
    0
  ).getDay();

  const nextDays = 7 - lastDayIndex - 1;

  const months = [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December",
  ];


  document.querySelector(".date h1").innerHTML = months[date.getMonth()];
  document.querySelector(".date p").innerHTML = new Date().toDateString();

  let days = "";

  for (let x = firstDayIndex; x > 0; x--) {
    days += `<div class="prev-date">${prevLastDay - x + 1}</div>`;
    
  } 

  for (let i = 1; i <= lastDay; i++) {
      if (
        i >= new Date().getDate() &&
        date.getMonth() >= new Date().getMonth()
      ) {
        days += `<div class="green day" data-date="${i}-${date.getMonth() + 1}">${i}</div>`;
      } else {
        days += `<div class="red day" data-date="${i}-${date.getMonth() + 1}">${i}</div>`;
      }
    }

  monthDays.innerHTML = days;
};

document.querySelector(".prev").addEventListener("click", () => {
  date.setMonth(date.getMonth() - 1);
  renderCalendar();
});

document.querySelector(".next").addEventListener("click", () => {
  date.setMonth(date.getMonth() + 1);
  renderCalendar();
});

renderCalendar();

const dateEls = Array.from(document.querySelectorAll('.day'));
dateEls.forEach((dateEl) => {
    dateEl.addEventListener('click', (event) => {
        console.log(event.currentTarget.dataset.date);
    });
});
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: "Quicksand", sans-serif;
  }
  
  html {
    font-size: 62.5%;
  }
  
  .leaves {
    width: 100%;
    /* height: 100vh; */
    background-color: #12121f;
    color: #eee;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  
  .container {
    width: 100%;
    height: 100vh;
    background-color: #12121f;
    color: #eee;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  
  .calendar {
    width: 45rem;
    height: 52rem;
    background-color: #222227;
    box-shadow: 0 0.5rem 3rem rgba(0, 0, 0, 0.4);
  }
  
  .month {
    width: 100%;
    height: 12rem;
    background-color: #167e56;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 2rem;
    text-align: center;
    text-shadow: 0 0.3rem 0.5rem rgba(0, 0, 0, 0.5);
  }
  
  .month i {
    font-size: 2.5rem;
    cursor: pointer;
  }
  
  .month h1 {
    font-size: 3rem;
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: 0.2rem;
    margin-bottom: 1rem;
  }
  
  .month p {
    font-size: 1.6rem;
  }
  
  .weekdays {
    width: 100%;
    height: 5rem;
    padding: 0 0.4rem;
    display: flex;
    align-items: center;
  }
  
  .weekdays div {
    font-size: 1.5rem;
    font-weight: 400;
    letter-spacing: 0.1rem;
    width: calc(44.2rem / 7);
    display: flex;
    justify-content: center;
    align-items: center;
    text-shadow: 0 0.3rem 0.5rem rgba(0, 0, 0, 0.5);
  }
  
  .days {
    width: 100%;
    display: flex;
    flex-wrap: wrap;
    padding: 0.2rem;
  }
  
  .days div {
    font-size: 1.4rem;
    margin: 0.3rem;
    width: calc(40.2rem / 7);
    height: 5rem;
    display: flex;
    justify-content: center;
    align-items: center;
    text-shadow: 0 0.3rem 0.5rem rgba(0, 0, 0, 0.5);
    transition: background-color 0.2s;
  }
  
  .days div:hover:not(.today) {
    background-color: #262626;
    border: 0.2rem solid #777;
    cursor: pointer;
  }
  
  .prev-date,
  .fcc-other-month { 
    visibility:hidden;
 }
  .next-date {
    opacity: 0.5;
  }
  
  .green {
    background-color: #167e56;
  }

  .red {
    background-color: red;
  }
<div class="leaves">
      <div class="calendar">
        <div class="month">
          <i class="fas fa-angle-left prev"></i>
          <div class="date">
            <h1></h1>
            <p></p>
          </div>
          <i class="fas fa-angle-right next"></i>
        </div>
        <div class="weekdays">
          <div>Sun</div>
          <div>Mon</div>
          <div>Tue</div>
          <div>Wed</div>
          <div>Thu</div>
          <div>Fri</div>
          <div>Sat</div>
        </div>
        <div class="days"></div>
      </div>
    </div>

Suggestion: Before the loop runs, you could also store the .getDate() and .getMonth() values in a variable for performance improvements.

Edit: The above part answers the onclick. For the year issue, you'll also need to compare the years in addition to the date and month.

Edit 2: To display it in the DOM, add an element like: <span id="selected-date"></span>, and in the click event listener, add: document.getElementById('selected-date').innerText = event.currentTarget.dataset.date;

Siddharth Bhansali
  • 2,017
  • 2
  • 10
  • 19
  • I would set listener on `days` div itself and check for dataset `document.querySelector('.days').addEventListener('click', (event) => { if (event.target.dataset.date) { console.log(event.target.dataset.date); } });` – Smollet777 Nov 13 '21 at 12:16
  • That would work, but OP wanted onclick on the day so I did that. And also, won't have to add the extra check for bubbling. – Siddharth Bhansali Nov 13 '21 at 12:20
  • Hi, I dont know why its not working on chrome when I run the server it says" Audit usage of navigator.userAgent, navigator.appVersion, and navigator.platform" on the console. If I want to show the selected date on the same page as the calendar can I add document.getElementById("data.date").innerHTML = "days"; in the add event listener of the js and

    Selected date is

    in the html.
    – Jin Nov 13 '21 at 14:16
  • Your first error is because of something else, read here: https://stackoverflow.com/questions/68982181/issue-audit-usage-of-navigator-useragent-navigator-appversion-and-navigator-p – Siddharth Bhansali Nov 13 '21 at 16:50
  • For the second, I've updated the answer again. – Siddharth Bhansali Nov 13 '21 at 16:54