javascriptonclicklistenerpikaday

Cannot stop a listener in javascript


I'm working with Pikaday (https://github.com/Pikaday/Pikaday). I'm trying to create a calendar with two months opened at the same time, which would allow to choose a date range. Everything works correctly except after I select my date range, the hovering effect, which allows to see the picked range, does not stop. It should stop after the second click.

It looks like this: https://i.imgur.com/ZvVbKwj.gif

Here is the relevant code fragment:

function addHoverListener(startDate) {
            var dates = document.querySelectorAll('.pika-button[data-pika-month="' + startDate.getMonth() + '"][data-pika-year="' + startDate.getFullYear() + '"]');
            var allDates = [];
        
            document.querySelectorAll('.pika-single').forEach(function(pikaSingle) {
                allDates.push(...pikaSingle.querySelectorAll('.pika-button'));
            });
        
            var firstCalendar = document.querySelector('.pika-single').children[0];
            var secondCalendar = document.querySelector('.pika-single').children[1];
        
            function hoverHandler() {
                var date = this;
                var isHoveredDateInFirstCalendar = firstCalendar.contains(date);
                var isHoveredDateInSecondCalendar = secondCalendar.contains(date);
                var hoveredDate = new Date(date.getAttribute('data-pika-year'), date.getAttribute('data-pika-month'), date.getAttribute('data-pika-day'));
        
                allDates.forEach(function(date) {
                    applyStylesOnDate(date, startDate, hoveredDate, firstCalendar, secondCalendar, isHoveredDateInFirstCalendar, isHoveredDateInSecondCalendar);
                });
            }
        
            function clickHandler() {
                console.log("Date clicked");
                this.removeEventListener('mouseover', hoverHandler);
                console.log("Hover event listener removed");
            }
        
            allDates.forEach(function(date) {
                date.addEventListener('mouseover', hoverHandler);
                date.addEventListener('click', clickHandler);
            });
        
            console.log("Hover listeners added");
        }

and here is nearly the whole code I wrote if necessary:

Pikaday = function(options) {
        var self = this,
            opts = self.config(options),
            firstSelectedDate = null,
            secondSelectedDate = null;
    
        self._onMouseDown = function(e) {
            if (!self._v) return;
            e = e || window.event;
            var target = e.target || e.srcElement;
            if (!target) return;
    
            if (!hasClass(target, 'is-disabled')) {
                if (hasClass(target, 'pika-button') && !hasClass(target, 'is-empty') && !hasClass(target.parentNode, 'is-disabled')) {
                    if (!firstSelectedDate) {
                        firstSelectedDate = new Date(target.getAttribute('data-pika-year'), target.getAttribute('data-pika-month'), target.getAttribute('data-pika-day'));
                        target.classList.add('first-selected');
                        self.setDate(firstSelectedDate);
                        addHoverListener(firstSelectedDate);
                    } else if (!secondSelectedDate) {
                        secondSelectedDate = new Date(target.getAttribute('data-pika-year'), target.getAttribute('data-pika-month'), target.getAttribute('data-pika-day'));
                        target.classList.add('second-selected');
                        if (firstSelectedDate.getTime() > secondSelectedDate.getTime())
                            opts.field.value = secondSelectedDate.toDateString() + " - " + firstSelectedDate.toDateString();
                        else
                            opts.field.value = firstSelectedDate.toDateString() + " - " + secondSelectedDate.toDateString();
                        if (opts.blurFieldOnSelect && opts.field) opts.field.blur();
                    }
                    if (firstSelectedDate && secondSelectedDate) {
                        firstSelectedDate = null;
                        secondSelectedDate = null;
                    }
                } else if (hasClass(target, 'pika-prev')) {
                    self.prevMonth();
                } else if (hasClass(target, 'pika-next')) {
                    self.nextMonth();
                }
            }
            if (!hasClass(target, 'pika-select')) {
                if (e.preventDefault) e.preventDefault();
                else {
                    e.returnValue = false;
                    return false;
                }
            } else self._c = true;
        };
    
    
        function addHoverListener(startDate) {
            var allDates = [];
        
            document.querySelectorAll('.pika-single').forEach(function(pikaSingle) {
                allDates.push(...pikaSingle.querySelectorAll('.pika-button'));
            });
        
            var firstCalendar = document.querySelector('.pika-single').children[0];
            var secondCalendar = document.querySelector('.pika-single').children[1];
        
            function hoverHandler() {
                var date = this;
                var isHoveredDateInFirstCalendar = firstCalendar.contains(date);
                var isHoveredDateInSecondCalendar = secondCalendar.contains(date);
                var hoveredDate = new Date(date.getAttribute('data-pika-year'), date.getAttribute('data-pika-month'), date.getAttribute('data-pika-day'));
        
                allDates.forEach(function(date) {
                    applyStylesOnDate(date, startDate, hoveredDate, firstCalendar, secondCalendar, isHoveredDateInFirstCalendar, isHoveredDateInSecondCalendar);
                });
            }
        
            function clickHandler() {
                console.log("Date clicked");
                this.removeEventListener('mouseover', hoverHandler);
                console.log("Hover event listener removed");
            }
        
            allDates.forEach(function(date) {
                date.addEventListener('mouseover', hoverHandler);
                date.addEventListener('click', clickHandler);
            });
        
            console.log("Hover listeners added");
        }
        
    
        function applyStylesOnDate(date, startDate, hoveredDate, firstCalendar, secondCalendar, isHoveredDateInFirstCalendar, isHoveredDateInSecondCalendar) {
            var dateObj = new Date(date.getAttribute('data-pika-year'), date.getAttribute('data-pika-month'), date.getAttribute('data-pika-day'));
            var button = document.querySelector('.is-selected .pika-button, .has-event .pika-button');
    
            if (dateObj.getTime() === hoveredDate.getTime() && dateObj.getTime() > startDate.getTime()) {
                date.classList.add('hovered-date-future');
                button.style.borderTopLeftRadius = '3px';
                button.style.borderBottomLeftRadius = '3px';
                button.style.borderTopRightRadius = '0px';
                button.style.borderBottomRightRadius = '0px';
            } else if (dateObj.getTime() === hoveredDate.getTime() && dateObj.getTime() < startDate.getTime()) {
                date.classList.add('hovered-date-past');
                button.style.borderTopLeftRadius = '0px';
                button.style.borderBottomLeftRadius = '0px';
                button.style.borderTopRightRadius = '3px';
                button.style.borderBottomRightRadius = '3px';
            } else if ((isHoveredDateInFirstCalendar && dateObj >= startDate && dateObj <= hoveredDate) ||
                (isHoveredDateInSecondCalendar && dateObj >= startDate && dateObj <= hoveredDate)) {
                date.classList.add('between-selected');
                date.classList.remove('hovered-date-future');
                date.classList.remove('hovered-date-past');
            } else if ((isHoveredDateInFirstCalendar && dateObj <= startDate && dateObj >= hoveredDate) ||
                (isHoveredDateInSecondCalendar && dateObj <= startDate && dateObj >= hoveredDate)) {
                date.classList.add('between-selected');
                date.classList.remove('hovered-date-future');
                date.classList.remove('hovered-date-past');
            } else {
                date.classList.remove('between-selected');
                date.classList.remove('hovered-date-future');
                date.classList.remove('hovered-date-past');
            }
        }```



I tried what can be seen in the code. Also tried to add some booleans and set them to false after the click. I'm new to javascript.

Solution

  • Use this instead:

    function clickHandler(e) {
        console.log("Date clicked");
        e.target.removeEventListener('mouseover', hoverHandler); 
        console.log("Hover event listener removed");
    }
    

    The this keyword refers to the window object. e.target is the element which was clicked.

    Edit:

    I saw your code again and found that you are removing the click listener from only the element that was clicked, but you have added the listener to all the elements.

    Here's the code that should work

    function clickHandler() {
        console.log("Date clicked");
        dates.forEach(date => {
            date.removeEventListener('mouseover', hoverHandler);
        })
        console.log("Hover event listener removed");
    }
    

    Hope this works