skip to Main Content

I’d like to convert jQuery to Pure JavaScript but it doesn’t work.

jQuery:

(document).ready(function()
{
    $(".js-all-btn").on("click", this, function()
    {
        $(this).toggleClass("active");
        $(".js-all-content").toggleClass("a-block");
    }
);
});

To Pure:

document.addEventListener("DOMContentLoaded", function()
{
    document.querySelector(".js-all-btn").on("click", this, function()
    {
        document.querySelector(this).toggleClass("active");
        document.querySelector(".js-all-content").toggleClass("a-block");
    });
});

Result:
document.querySelector(...).on is not a function

As you can see unfortunately doesn’t work. So, exactly how do we solve that?

As I couldn’t solve the problem permanently, I asked over here and my expectation is that this problem will be solved.

2

Answers


  1. jQuery is delegating. It is not clear how to solve this without knowing if you have one or more buttons with that class

    If only ONE button, do this

    document.addEventListener("DOMContentLoaded", () => {
      document.querySelector("button.js-all-btn").addEventListener("click", (e) => {
        e.target.toggleClass("active");
        document.querySelector(".js-all-content").toggleClass("a-block");
      });
    });
    

    If more than one button you can delegate

    document.addEventListener("DOMContentLoaded", () => {
      document.querySelector("someSelectorWrappingTheButtons").addEventListener("click", (e) => {
        const tgt = e.target.closest("button.js-all-btn");
        if (!tgt) return; // not the button
        tgt.toggleClass("active");
        document.querySelector(".js-all-content").toggleClass("a-block"); // if this is a sibling of the js-all-btn then you need to navigate instead.
      });
    });
    
    Login or Signup to reply.
  2. It’s safer to also check for the current readyState in case the all the load events have already fired.

    If you have multiple buttons/contents you should use querySelectorAll, if you only want to get the first/single you can use querySelector.

    Have a look at the following example with a bit html and css:

    if (document.readyState === "complete") onLoad();
    else addEventListener("load", onLoad);
    
    function onLoad() {
      const buttons = document.querySelectorAll(".js-all-btn");
      for (const button of buttons) button.addEventListener("click", onToggleButtonClick);
    }
    
    /**
     * @this {HTMLButtonElement} the target button
     */
    function onToggleButtonClick() {
      this.classList.toggle("active");
    
      const contents = document.querySelectorAll(".js-all-content");
      for (const content of contents) content.classList.toggle("a-block");
    }
    .active {
      background: red;
    }
    
    .a-block {
      background: blue;
    }
    <button class="js-all-btn"> Button 1 </button>
    <button class="js-all-btn"> Button 2 </button>
    
    <div class="js-all-content"> Content 1 </div>
    <div class="js-all-content"> Content 2 </div>

    Mostly ES5 (IE11 Compatible)

    if (document.readyState === "complete") onLoad();
    else addEventListener("load", onLoad);
    
    function onLoad() {
      var buttons = document.querySelectorAll(".js-all-btn");
      for (var index = 0; index < buttons.length; index++) {
        var button = buttons[index];
        button.addEventListener("click", onToggleButtonClick);
      }
    }
    
    /**
     * @this {HTMLButtonElement} the target button
     */
    function onToggleButtonClick() {
      this.classList.toggle("active");
    
      var contents = document.querySelectorAll(".js-all-content");
      for (var index = 0; index < contents.length; index++) {
        var content = contents[index];
        content.classList.toggle("a-block");
      }
    }
    .active {
      background: red;
    }
    
    .a-block {
      background: blue;
    }
    <button class="js-all-btn"> Button 1 </button>
    <button class="js-all-btn"> Button 2 </button>
    
    <div class="js-all-content"> Content 1 </div>
    <div class="js-all-content"> Content 2 </div>

    If you need to support an older version of IE you might have to add a polyfill for classList.toggle

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search