0

I am trying to use JavaScript to toggle a button from the label "Connect" to the label "Forget" when clicked, and then toggle the button back to "Connect" when clicked again.

My code does not toggle the button like I expect it to. The code is in a view template (.cshtml) file in an ASP.NET Core MVC app. I am also open to answers that use JQuery to achieve my goal.

HTML:

<button type="button" class="buttonOne">Connect</button>

Code:

const $ = document.querySelector.bind(document);
$(".buttonOne").addEventListener("click", (e) => {
  let clicked = false;
  if (clicked) {
    e.target.innerText = "Forget";
  } else {
    e.target.innerText = "Connect";
  }
  clicked = !clicked;
});

$(".buttonTwo").addEventListener("click", (e) => {
  let clicked = false;
  if (clicked) {
    e.target.innerText = "Forget";
  } else {
    e.target.innerText = "Connect";
  }
  clicked = !clicked;
});

$(".buttonThree").addEventListener("click", (e) => {
  let clicked = false;
  if (clicked) {
    e.target.innerText = "Forget";
  } else {
    e.target.innerText = "Connect";
  }
  clicked = !clicked;
});

Update

This code changes the button from "Connect" to "Forget" but you need to click the button twice for some reason, and if you click the button again the state of the button doesn't return to "Connect". The "onclick" HTML attribute is also needed, not sure why.

<button type="button" class="buttonOne" onclick="myFunction2();">Connect</button>

<script>

function myFunction2(){
    const $ = document.querySelector.bind(document);

        $(".buttonOne").addEventListener("click", (e) => {
            let clicked = false;
            if (clicked)
            {
                e.target.innerText = "Connect";
            } else {
                e.target.innerText = "Forget";

            }
            
            clicked = !clicked;
        });

        $(".buttonTwo").addEventListener("click", (e) =>
        {
            let clicked = false;
            if (clicked)
            {
                e.target.innerText = "Forget";
            } else {
                e.target.innerText = "Connect";
            }

            clicked = !clicked;
        });
        
        $(".buttonThree").addEventListener("click", (e) => {
            let clicked = false;
            if (clicked)
            {
                e.target.innerText = "Forget";
            }else {
                e.target.innerText = "Connect";
            }

            clicked = !clicked;
    });
    }
</script>

Update 2

Thanks to @John Ronald' comment (@mplungjan's answer) I wrote the following code that works:

const $ = document.querySelector.bind(document);

let clickedOne = false;
let clickedTwo = false;
let clickedThree = false;
$(".buttonOne").addEventListener("click", (e) => {
  // When method executes it means the button has been clicked      
  if (clickedOne) {
    // When unclicked change button label to "Connect"
    e.target.innerText = "Connect";
  } else {
    // When first clicked change button label to "Forget"
    e.target.innerText = "Forget";

  }

  clickedOne = !clickedOne;
});

$(".buttonTwo").addEventListener("click", (e) => {
  if (clickedTwo) {
    e.target.innerText = "Connect";
  } else {
    e.target.innerText = "Forget";
  }

  clickedTwo = !clickedTwo;
});

$(".buttonThree").addEventListener("click", (e) => {
  if (clickedThree) {
    e.target.innerText = "Connect";
  } else {
    e.target.innerText = "Forget";
  }

  clickedThree = !clickedThree;
});
<button class="buttonOne">Connect</button>
<button class="buttonTwo">Connect</button>
<button class="buttonThree">Connect</button>

Update 3

The buttons in my HTML document contained an anchor element with an empty href attribute value (<a href="">) which caused the button to flash the label "Forget" when clicked, instead of the button being toggled to "Forget" until it was clicked again. This is why when using the JavaScript code in Update 2 the button was not toggled when clicked.

bit
  • 443
  • 1
  • 7
  • 19
  • It is VERY confusing you bind `$` as if it is jQuery. Please click edit, then `[<>]` and provide a [mcve] of relevant RENDERED HTML, relevant CSS and any frameworks. It is not at all obvious what your expected result is `let clicked = false;` is not very useful – mplungjan Jan 22 '21 at 12:21
  • 3
    If you set "clicked=false" inside the onclick method, it will always be false. – John Ronald Jan 22 '21 at 12:23
  • @JohnRonald How so? The `clicked = !clicked` flips the boolean. – bit Jan 22 '21 at 12:37
  • Yeah, you flip it at the end of the method, which is pretty useles. Everytime you call the onclick method, it gets rewrited to false. Moreover it is only local variable. You would need to set it as global variable. – John Ronald Jan 22 '21 at 12:42

2 Answers2

1

Your let clicked = false; in the beginning of the function will thwart your attempts every time.

If you set it to false at the beginning of the function it is false until you flip it to true. Next time you click, it is set to false before you test it.

I suggest you delegate. Change the class to ID and the class to button

Then delegate from a container

The test is the text on the button - no need for a clicked var now If you are going to have different languages, use a data-attribute on the button instead of some global boolean

document.getElementById("buttonContainer").addEventListener("click", function(e) {
  const tgt = e.target;
  if (tgt.classList.contains("button")) {
    const text = tgt.textContent;
    console.log("Clicked",tgt.id,"to",text)
    tgt.textContent = text === "Forget" ? "Connect" : "Forget"
  }
});
<div id="buttonContainer">
  <button id="buttonOne" class="button">Connect</button>
  <button id="buttonTwo" class="button">Connect</button>
  <button id="buttonThree" class="button">Connect</button>
</div>
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • Can you explain why the `let clicked = false;` thwarts my attempts every time? Maybe I'm missing something. – bit Jan 22 '21 at 12:38
  • @BlackPanther In my script I have ONE event handler, no global vars and no need for a special variable to hold "clicked" - just testing the state of each button when the button is clicked – mplungjan Jan 22 '21 at 13:36
  • 1
    Your answer is very concise, and still understandable and clear. – bit Jan 22 '21 at 14:23
  • https://stackoverflow.com/questions/2613310/ive-heard-global-variables-are-bad-what-alternative-solution-should-i-use – mplungjan Jan 22 '21 at 14:26
0

You could declare 3 global variables for each button. It should look something like this:

let clicked1 = false;
let clicked2 = false;
let clicked3 = false;

    const $ = document.querySelector.bind(document);
    $(".buttonOne").addEventListener("click", (e) => {
      
      if (clicked1) {
        e.target.innerText = "Forget";
      } else {
        e.target.innerText = "Connect";
      }
      clicked1 = !clicked1;
    });

    $(".buttonTwo").addEventListener("click", (e) => {
     
      if (clicked2) {
        e.target.innerText = "Forget";
      } else {
        e.target.innerText = "Connect";
      }
      clicked2 = !clicked2;
    });

    $(".buttonThree").addEventListener("click", (e) => {
     
      if (clicked3) {
        e.target.innerText = "Forget";
      } else {
        e.target.innerText = "Connect";
      }
      clicked3 = !clicked3;
    });
John Ronald
  • 135
  • 8
  • 2
    Not my downvote, but no-one likes global variables if they're not needed – freedomn-m Jan 22 '21 at 13:10
  • @freedomn-m What's wrong with where he declared the variables? – bit Jan 22 '21 at 13:20
  • 2
    The code is inefficient and pollutes the global scope. As you see in my answer, the simplest test is just testing the button attribute or text. Also in my answer you see how delegation handles all three buttons with ONE script. It is called DRY (don't repeat yourself) – mplungjan Jan 22 '21 at 13:34
  • @BlackPanther It's not "wrong". Getting a downvote when you've spent time to answer a question can be frustrating, so I wanted to provide a *suggestion* of why the anonymous (non-commenter) might have downvoted. – freedomn-m Jan 22 '21 at 16:39
  • @freedomn-m Thanks for advice. – John Ronald Jan 22 '21 at 16:42