Home > Enterprise >  Javascript on button click not working if button title is styled/underlined
Javascript on button click not working if button title is styled/underlined

Time:08-12

I have the following code

const collapse = (elem,forceClose) => {
  const content = elem.nextElementSibling;
  if (!content || !content.matches(".content")) return; // no content after the element, so leave
  if (forceClose) elem.classList.remove("active"); // passed force or nothing passed
  else elem.classList.toggle("active");
  content.style.maxHeight = elem.classList.contains("active") ? content.scrollHeight   "px" : null;
};

const buttons = document.querySelectorAll(".collapsible");
document.getElementById("container").addEventListener("click", e => {
  const tgt = e.target;
  if (!tgt.matches(".collapsible")) return; // clicked on something not a button
  if (tgt.matches(".all")) { // special button
    const close = container.querySelectorAll(".collapsible.active").length > 0;
    buttons.forEach(but => collapse(but,close)); 
  } else {
    collapse(tgt);
  }
});
.content    {
    max-height:0;
    overflow:hidden;

}
<div id="container">

<button >XXXXXXXXXX <u>YYYYYYYYYY</u></button>

<div  style="">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>

</div>

Click on the XXXXXXXXXX on the button to hide and show the content. This is working as expected.

But if you click on YYYYYYYYYY it's not working, just because YYYYYYYYYY is underlined.

Why doesn't the buttons function not work any more just because of the underlined text? How can I solve this? I need the button to work and the text underlined.

CodePudding user response:

It's because e.target points to the exact element that triggered the handler when the event bubbles up, in that case the, <u></u> node not the button.

Think of it this way, the only reason the event fires even though you added the listener to the container, not the button is because the event bubbles up, finds the listener on one of the parents, and triggers the handler.

I do think you should add the event handler to the button itself instead of the container, but if you need it to stay as it is, you can check the event.composedPath() which has all the elements/objects that the event bubbles through and then check if that path contains the button.

If you decide to add the handler to the button you'll also need to use e.currentTarget which references the element which the handler callback is assigned to. So that even if you click on <u></u>, when the event bubbles to the button, currentTarget will reference the button itself.

Here's a solution where I kept your approach as it as, but used composedPath() instead of event.target

const collapse = (elem,forceClose) => {
  const content = elem.nextElementSibling;
  if (!content || !content.matches(".content")) return; // no content after the element, so leave
  if (forceClose) elem.classList.remove("active"); // passed force or nothing passed
  else elem.classList.toggle("active");
  content.style.maxHeight = elem.classList.contains("active") ? content.scrollHeight   "px" : null;
};

const buttons = document.querySelectorAll(".collapsible");
document.getElementById("container").addEventListener("click", e => {
  const pathArray = [...e.composedPath()]
  console.log('Event Target: ', e.target)
  // console.log(pathArray); // This is a bit laggy in the snippet, but uncomment it if you want to see what the even path looks like.
  
  const collapseButton = pathArray.find(obj => obj?.classList?.contains('collapsible'))
  const allButton = pathArray.find(obj => obj?.classList?.contains('all'))
  
  if (!collapseButton && !allButton) return; // clicked on something not a button
  if (allButton) { // special button
    const close = container.querySelectorAll(".collapsible.active").length > 0;
    buttons.forEach(but => collapse(but,close)); 
  } else {
    collapse(collapseButton);
  }
});
.content {
  max-height: 0;
  overflow: hidden;
}
<div id="container">

  <button >XXXXXXXXXX <u>YYYYYYYYYY</u></button>

  <div  style="">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</div>

</div>

CodePudding user response:

You're wrapping YYYYYYYYYY into an <u> tag, so when you click on it, the onClick event of <u> tag was called, not <button>. Try it with <div> or <nav>,... will return the same effect.

  • Related