I have a calendar that looks like this, styled using Tailwind CSS:
8 Wednesday is currently clicked, so it has a pink background and a pink shadow. The 7th one is the previously clicked element, that's why it only has pink shadow (I removed the pink background class but kept the pink shadow).
What I want is to keep the latest previously clicked element so that I can add a pink shadow, but only to the latest element, not all previously clicked elements.
This is what my JavaScript code looks like:
//select needed elements from HTML
const calendarDates = document.querySelectorAll('.clickable')
const dateDisplay = document.getElementById('show-details');
const selectedDateDayElement = document.getElementById('selected-date-day');
const selectedDateElement = document.getElementById('selected-date');
let latestClicked = null;
let latestPreviouslyClicked = null;
// if there is no date, dont add hover efects
for (let i = 0; i < calendarDates.length; i++) {
if (calendarDates[i].textContent.trim() === '') {
calendarDates[i].classList.remove('hover:bg-pink-500', 'hover:shadow-md', 'hover:cursor-pointer', 'hover:shadow-pink-500');
calendarDates[i].classList.add('empty')
}
}
// select only elements that are not empty
const clickableDates = document.querySelectorAll('.clickable:not(.empty)');
clickableDates.forEach(dateElement => {
dateElement.addEventListener('click', () => {
const dateValue = dateElement.textContent.trim();
const year = 2017;
const month = 1;
if (latestClicked !== null) {
latestPreviouslyClicked = latestClicked;
latestClicked = null;
latestPreviouslyClicked.classList.remove('bg-pink-500');
}
dateElement.classList.add('bg-pink-500', 'shadow-md', 'shadow-pink-500');
latestClicked = dateElement;
const selectedDate = new Date(year, month, parseInt(dateValue));
const daysOfWeek = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const dayOfWeek = daysOfWeek[selectedDate.getDay()];
selectedDateDayElement.textContent = dayOfWeek;
selectedDateElement.textContent = dateValue;
dateDisplay.style.display = 'block';
});
});
// Close the date details when clicked outside, and this works at it should
document.addEventListener('click', event => {
if (!event.target.classList.contains('clickable')) {
clickableDates.forEach(element => {
element.classList.remove('bg-pink-500');
});
dateDisplay.style.display = 'none';
}
});
The problem I'm facing is that it retains the shadow of all previously clicked elements:
The expected behavior is:
Okay, I also misread your question.
The problem lies in part
if (latestClicked !== null) { latestPreviouslyClicked = latestClicked; latestClicked = null; latestPreviouslyClicked.classList.remove('bg-pink-500'); }You actually only removed the background from the
latestClickedelement, never the shadow style.This should work:
if(latestPreviouslyClicked !== null) { latestPreviouslyClicked.classList.remove('shadow-md', 'shadow-pink-500'); } // update second latest element after changing the classes latestPreviouslyClicked = latestClicked; if(latestClicked !== null) { latestClicked.classList.remove('bg-pink-500'); } latestClicked = dateElement;The important part is to mutate the element before reassigning it to the next element.
Alternatively, if optional link works in your environment (bundler or only new browser support):
latestPreviouslyClicked?.classList.remove('shadow-md', 'shadow-pink-500'); // update second latest element after changing the classes latestPreviouslyClicked = latestClicked; latestClicked?.classList.remove('bg-pink-500'); latestClicked = dateElement;