yayahyayah
yayahyayah

Reputation: 11

Why I have to click on a button twice for the event to happen - javascript?

Context: Goal: Mimic the cancel sent email button in gmail. Current problem: I have to click the Cancel button twice for it to work.

Detail: The following code creates a Send button. After it was clicked, a countdown paragraph will display and started to count down from 10 to 0 and the button will change from Send to Cancel. The Cancel button is supposed to display a message (Sent email has been recalled!) immediately after the button was clicked. However, currently, I have to click the Cancel button twice for the recall message to show up. I wonder which line of code causes the problem?

Code below

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>DOM Demo</title>
    <link ref="icon" href="favicon.ico">
</head>

<body>
    <main>
        <div>
            <button id="action-button">Send</button>
            <p id="countdown-message"></p>
        </div>

    </main>
    <script>
        'use strict'

        const button = document.getElementById('action-button');
        button.addEventListener('click', changeButtonText)

        const countdownMessage = document.getElementById('countdown-message');
        let sec = 10;
        let timeoutId = 0;
        
        function changeButtonText() {
            if (button.innerText === 'Send') {
                button.innerText = 'Cancel';
                countDown();
            }
            else if (button.innerText === 'Cancel') {
                button.addEventListener('click',cancelSent);
            }
        }

        function countDown() {
            if (sec > 0) {
                showCountdownMessage();
                sec--;
                timeoutId = setTimeout(countDown, 1000);
            } else {
                showSentMessage();
            }
        }

        function cancelSent(){
            clearTimeout(timeoutId);
            countdownMessage.innerText = 'Sent email has been recalled!'
        }

        function showCountdownMessage() {
            countdownMessage.innerText = `The email will be sent in ${sec} seconds`;
        }

        function showSentMessage() {
            countdownMessage.innerText = 'Email has been sent!'
        }
    </script>
</body>

</html>

Upvotes: 0

Views: 159

Answers (2)

Biswas Sampad
Biswas Sampad

Reputation: 451

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>DOM Demo</title>
</head>

<body>
    <main>
        <div>
            <button id="action-button">Send</button>
            <p id="countdown-message"></p>
        </div>

    </main>
    <script>
        'use strict'

        const button = document.getElementById('action-button');
        button.addEventListener('click', changeButtonText)

        const countdownMessage = document.getElementById('countdown-message');
        let sec = 10;
        let timeoutId = 0;
        
        function changeButtonText() {
            if (button.innerText === 'Send') {
                button.innerText = 'Cancel';
                countDown();
            }
            else if (button.innerText === 'Cancel') {
                cancelSent()
            }
            // efficient way to do the same 
            // switch(button.innerText){
            //     case 'Send':
            //         button.innerText = 'Cancel';
            //         countDown();
            //         break;
            //     case 'Cancel':
            //         cancelSent()
            // }
        }

        function countDown() {
            if (sec > 0) {
                showCountdownMessage();
                sec--;
                timeoutId = setTimeout(countDown, 1000);
            } else {
                showSentMessage();
            }
        }

        function cancelSent(){
            clearTimeout(timeoutId);
            countdownMessage.innerText = 'Sent email has been recalled!'
        }

        function showCountdownMessage() {
            countdownMessage.innerText = `The email will be sent in ${sec} seconds`;
        }

        function showSentMessage() {
            countdownMessage.innerText = 'Email has been sent!'
        }
    </script>
</body>

</html>

Upvotes: 0

A Haworth
A Haworth

Reputation: 36456

The problem is that you don't act on the user clicking Cancel straightaway. Instead you create a new event listener so the system won't do anything until the user clicks again and that event listener is invoked.

Remove the creation of a new event listener and instead call the cancelling function straightaway. Note, you also need to reset sec to its initial value otherwise the user gets a decreasing amount of time in which to decide to cancel the send.

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>DOM Demo</title>
  <link ref="icon" href="favicon.ico">
</head>

<body>
  <main>
    <div>
      <button id="action-button">Send</button>
      <p id="countdown-message"></p>
    </div>

  </main>
  <script>
    'use strict'

    const button = document.getElementById('action-button');
    button.addEventListener('click', changeButtonText)

    const countdownMessage = document.getElementById('countdown-message');
    let sec = 10;
    let timeoutId = 0;

    function changeButtonText() {
      if (button.innerText === 'Send') {
        button.innerText = 'Cancel';
        countDown();
      } else if (button.innerText === 'Cancel') {
        // button.addEventListener('click',cancelSent);
        cancelSent();
        button.innerText = 'Send';
        sec = 10;
      }
    }

    function countDown() {
      if (sec > 0) {
        showCountdownMessage();
        sec--;
        timeoutId = setTimeout(countDown, 1000);
      } else {
        showSentMessage();
      }
    }

    function cancelSent() {
      clearTimeout(timeoutId);
      countdownMessage.innerText = 'Sent email has been recalled!'
    }

    function showCountdownMessage() {
      countdownMessage.innerText = `The email will be sent in ${sec} seconds`;
    }

    function showSentMessage() {
      countdownMessage.innerText = 'Email has been sent!'
    }
  </script>
</body>

</html>

Upvotes: 1

Related Questions