Home > Net >  Optimizing JS onclick button issue w/o jQuery
Optimizing JS onclick button issue w/o jQuery

Time:10-27

So lately I've been trying to make a "SHOW MORE" and "SHOW LESS" feature with embedded SVG.

The code seems to be working fine, although each time I add another button I have to create completly new function therefore I was wondering if you could help me optimize my code.

Currently it looks like this:

<!-- HTML CODE -->
        <button id="hideShow" >SHOW MORE
          <svg id="showMoreSVG" width="13px" height="10px" viewBox="0 2 13 10">
            <path id="showMorePATH" d="M 1 5 L 1 5 L 5 9 L 9 5 L 5 9"></path>
          </svg>
        </button>
// js code
var button = document.getElementById("hideShow");
var content = document.getElementById("more-text");
let text = button.innerHTML.replace("MORE", "LESS");
let textR = button.innerHTML.replace("LESS", "MORE");

button.onclick = function () {
  if (content.className == "open") {
    content.className = "";
    document.getElementById("hideShow").innerHTML = textR;
    document.getElementById("showMoreSVG").setAttribute("viewBox", "0 2 13 10");
    document
      .getElementById("showMorePATH")
      .setAttribute("d", "M 1 5 L 1 5 L 5 9 L 9 5 L 5 9");
  } else {
    content.className = "open";
    document.getElementById("hideShow").innerHTML = text;
    document
      .getElementById("showMoreSVG")
      .setAttribute("viewBox", "0 -2 13 10");
    document
      .getElementById("showMorePATH")
      .setAttribute("d", "M 1 5 L 1 5 L 5 1 L 9 5 L 5 1");
  }
};

Result as img:

show more button

show less button

It works based on changing max-height property in css class that is different depending on size of text (some are smaller, some are larger). For example:

#more-text,
#more-text2 {
  max-height: 0px;
  overflow: hidden;
  transition: max-height 0.7s ease;
}
#more-text.open {
  max-height: 1600px;
  transition: max-height 0.7s ease;
}
#more-text2.open {
  max-height: 600px;
}

I know that the part of css code can be optimized with jQuery but I don't want to implement it on my website. Rather vanilla javascript or some npm package.

Also I do realize that content.className = "open"; is invalid way to change class, this is something I have on my todo list so please don't bother with that part.

Any help is much appreciated.

CodePudding user response:

Here's a reusable way to do it (though I can't seem to test the SVG - I may have gotted the up/down confused). Basically you initialize all more/less buttons at once (in case there are more than one) and you structure your HTML so each more/less instance is in it's own container. Then you can use closest(selector) and querySelector(selector) to target the elements you want without using all those ID tags - the ID tags are usefull for somethings but in your case you were reusing them which is strictly forbidden. There's no need for them as you can see.

// js code
let buttons = document.querySelectorAll(".hideShow");

buttons.forEach(button => button.addEventListener('click', e => {
      let content = e.target.closest('.hs-container').querySelector('.inner-content');
      let closeme = content.classList.contains('open');
      content.classList.toggle('open')
      e.currentTarget.querySelector('span').innerText = closeme ? "SHOW MORE" : "SHOW LESS";
      let att = closeme ? ["0 -2 13 10", "M 1 5 L 1 5 L 5 1 L 9 5 L 5 1"] : ["0 2 13 10", "M 1 5 L 1 5 L 5 9 L 9 5 L 5 9"];
        e.currentTarget.querySelector('.icon').setAttribute('viewBox', att[0])
        e.currentTarget.querySelector('.icon path').setAttribute('d', att[1])
      }));
.inner-content {
  max-height: 0px;
  overflow: hidden;
  transition: max-height 0.7s ease;
}

.open {
  max-height: 1600px;
  transition: max-height 0.7s ease;
}

svg.icon {
  width: 13px;
  height: 10px;
}
<div class='hs-container'>
  <div class='inner-content'>Blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah blah
    blah blah blah blah blah blah blah blah blah</div>
  <button ><span>SHOW MORE</span> 
          <svg  viewBox="0 2 13 10">
            <path d="M 1 5 L 1 5 L 5 9 L 9 5 L 5 9"></path>
            </svg>
        </button>
</div>

CodePudding user response:

Attach a class to the buttons and use .getElementsByClassName to select them all then attach your event listener while looping/iterating over that collection of buttons. That way you are adding it to all of them at once. Have the listener call a handler function with this.id or this.innerHTML and use if then or a switch block to compartmentalize your code.

Note that dynamically created buttons will need to have the event listener attached after they're created. You can do that by simply calling the same attach function again. It will not put double events on the prior buttons as only one is allowed.

Use EventTarget.addEventListener()

  • Related