简体   繁体   中英

Two click functions, affecting the same div, the first work but second not - javascript

I have a button which opens a popup when clicked, and in this popup there is a close button to close the popup but that close button is not working!

Here is my code:

 var fromToDate = document.getElementById('from-to-date'); var openFromToDate = document.getElementById('open-from-to-date'); var closeFromToDate = document.getElementById('close-from-to-date'); openFromToDate.addEventListener('click', function() { fromToDate.classList.remove('dis-none'); }); closeFromToDate.addEventListener('click', function() { fromToDate.classList.add('dis-none'); });
 .dis-none { display: none; } /* To make the button visible here */.fa-times::after { content: 'X'; }
 <li id="open-from-to-date"> <span class="custom-span-style warning-bk date-span"> From: 2022-09-16 To: 2022-09-18 </span> <div class="from-to-date dis-none" id="from-to-date"> <div class="from-to-date-wrapper"> <div class="close-from-to-date" id="close-from-to-date"> <i class="fa fa-times" aria-hidden="true"></i> </div> </div> </div> </li>

The problem is that when you click the close button, two listeners fire: First, the close button listener fires and adds dis-none , but then the open "button" listener also fires and removes dis-none again. This is because the close button is contained within the open "button", so any click on the close button also constitutes a click on the open "button" at the same time.

You can easily check this by adding console.log statements to the two listeners.

The solution is therefore to not let the event bubble up to any listeners on parent elements once you handled it on the close button itself, which can be done using stopPropagation :

 var fromToDate = document.getElementById('from-to-date'); var openFromToDate = document.getElementById('open-from-to-date'); var closeFromToDate = document.getElementById('close-from-to-date'); openFromToDate.addEventListener('click', function() { fromToDate.classList.remove('dis-none'); }); closeFromToDate.addEventListener('click', function(e) { fromToDate.classList.add('dis-none'); e.stopPropagation(); // <---- THIS });
 .dis-none { display: none; } /* To make the button visible here */.fa-times::after { content: 'X'; }
 <li id="open-from-to-date"> <span class="custom-span-style warning-bk date-span"> From: 2022-09-16 To: 2022-09-18 </span> <div class="from-to-date dis-none" id="from-to-date"> <div class="from-to-date-wrapper"> <div class="close-from-to-date" id="close-from-to-date"> <i class="fa fa-times" aria-hidden="true"></i> </div> </div> </div> </li>

(Note: I also added the event argument e to the listener function so that we could call stopPropgation on it.)

The problem is when you're clicking on the "closer" you are also clicking on the "opener" as well, say not? See the code below.

 var fromToDate = document.getElementById('from-to-date'); var openFromToDate = document.getElementById('open-from-to-date'); var closeFromToDate = document.getElementById('close-from-to-date'); openFromToDate.addEventListener('click', function() { fromToDate.classList.remove('dis-none'); console.log("I opened"); }); closeFromToDate.addEventListener('click', function() { fromToDate.classList.add('dis-none'); console.log("I closed"); });
 .dis-none { display: none; }
 <li id="open-from-to-date"> <span class="custom-span-style warning-bk date-span">From: 2022-09-16 To: 2022-09-18</span> <div class="from-to-date dis-none" id="from-to-date"> <div class="from-to-date-wrapper"> <div class="close-from-to-date" id="close-from-to-date"> <i class="fa fa-times" aria-hidden="true"></i> Close! </div> </div> </div> </li>

Now you have two ways to correct this:

window.setTimeout

 var fromToDate = document.getElementById('from-to-date'); var openFromToDate = document.getElementById('open-from-to-date'); var closeFromToDate = document.getElementById('close-from-to-date'); openFromToDate.addEventListener('click', function() { fromToDate.classList.remove('dis-none'); }); closeFromToDate.addEventListener('click', function() { setTimeout(function() { fromToDate.classList.add('dis-none'); }, 2); });
 .dis-none { display: none; }
 <li id="open-from-to-date"> <span class="custom-span-style warning-bk date-span">From: 2022-09-16 To: 2022-09-18</span> <div class="from-to-date dis-none" id="from-to-date"> <div class="from-to-date-wrapper"> <div class="close-from-to-date" id="close-from-to-date"> <i class="fa fa-times" aria-hidden="true"></i> Close! </div> </div> </div> </li>

In this method, the removing method runs 2ms later which means two lines of JS code later.

Capture parameter of addEventListener which usually is overseen

RECOMMENDED

See this example:

 var fromToDate = document.getElementById('from-to-date'); var openFromToDate = document.getElementById('open-from-to-date'); var closeFromToDate = document.getElementById('close-from-to-date'); openFromToDate.addEventListener('click', function() { fromToDate.classList.remove('dis-none'); console.log("I'm opened"); }, true); //Magic happens here closeFromToDate.addEventListener('click', function() { fromToDate.classList.add('dis-none'); console.log("I'm closed"); });
 .dis-none { display: none; }
 <li id="open-from-to-date"> <span class="custom-span-style warning-bk date-span">From: 2022-09-16 To: 2022-09-18</span> <div class="from-to-date dis-none" id="from-to-date"> <div class="from-to-date-wrapper"> <div class="close-from-to-date" id="close-from-to-date"> <i class="fa fa-times" aria-hidden="true"></i> Close! </div> </div> </div> </li>

In this example, the capturing method of the opening event is set to true which means, the event listening is in the capturing phase instead of the bubbling phase which is the default.

In the capturing phase, the outmost event listener runs first so the opening event is captured first and closing event, next.

For more information, see here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM