skip to Main Content

I am learning JavaScript.
I was practicing applying closures but I got stuck and am not able to find the issue with my code.

function change_greeting() {
  let on_or_off = 1;
  return function button() {
    if (on_or_off) {
      document.getElementById("demo") = "Hello";
    } else {
      document.getElementById("demo") = "Goodbye";
    }
  }
}
const click = change_greeting();
<button onclick=click()>Click Me</button>
<p id="demo"></p>

I tried a similar example without mixing it up with events, at that time it succeeded. I am not sure as to what change I must bring to my code.

3

Answers


  1. You should rewrite this

        ...
        let on_or_off=1;
        return function button()
        {
        if(on_or_off)
        ...
    

    to this (add changing the value to make toggle work):

        ...
        let on_or_off=true;
        return function button()
        {
        on_or_off = !on_or_off;
        if(on_or_off)
        ...
    
    Login or Signup to reply.
    • to toggle on_or_off 1,0,1,0,etc… use the Remainder operator % after an increment: on_or_off = ++on_or_off % 2 or simply using XOR assignment on_or_off ^= 1;
    • avoid the use of on* inline attribute handlers. Use addEventListener() instead
    • use Node.textContent when you want to output a string to an Element’s content
    const elDemo = document.getElementById("demo");
    const elBtn = document.getElementById("btn");
    
    function change_greeting() {
    
      let on_or_off = 1;
      
      return function () {
        if (on_or_off) {
          elDemo.textContent = "Hello";
        } else {
          elDemo.textContent = "Goodbye";
        }
        
        on_or_off = ++on_or_off % 2; // loop 0,1,0,1,...
      }
    }
    
    const click = change_greeting(); // call and return closure fn
    elBtn.addEventListener("click", click);
    <button id="btn">Click Me</button>
    <span id="demo"></span>

    And here’s the example using XOR assignment:

    const elDemo = document.getElementById("demo");
    const elBtn = document.getElementById("btn");
    
    const change_greeting = ()  => {
      let isOn = 1;
      return () => {
        elDemo.textContent = isOn ? "Hello" : "Goodbye";
        isOn ^= 1; // toggle 0,1,0,1...
      }
    };
    
    const click = change_greeting();
    elBtn.addEventListener("click", click);
    <button id="btn">Click Me</button>
    <span id="demo"></span>

    For completeness, instead of using integers 1,0,1,0... you could instead use a boolean variable and switch it using isOn = !isOn

    const elDemo = document.querySelector("#demo");
    const elBtn = document.querySelector("#btn");
    
    const change_greeting = () => {
      let isOn = true;
      return () => {
        elDemo.textContent = isOn ? "Hello" : "Goodbye";
        isOn = !isOn; // toggle boolean
      }
    };
    
    elBtn.addEventListener("click", change_greeting());
    <button id="btn">Click Me</button>
    <span id="demo"></span>

    and, as you can see in the latest example, there’s no need to store the closure in a click variable. If not used elsewhere you can simply call it within the click handler .addEventListener("click", change_greeting());

    Additionally (as seen in this examples), you can replace the 5 lines of if/else with a readable, well known and loved Ternary (conditional) operator statement ? truthy : falsy

    Login or Signup to reply.
  2. Basing the toggle logic on a boolean value and making more out of the advantage of dealing with a created closure, the OP’s example code could be streamlined to something much more readable as …

    function createGreetingsToggleHandler(contentNode) {
      let isGoodbye = true;
    
      return function () {
        contentNode.textContent = isGoodbye && 'Hello' || 'Goodbye';
        isGoodbye = !isGoodbye;
      }
    }
    document
      .querySelector('button')
      .addEventListener(
        'click',
        createGreetingsToggleHandler(
          document.querySelector('#greetings')
        )
      );
    <button>Click Me</button>
    <p id="greetings"></p>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search