-1

I'm making a game that generates four buttons with different hidden values. When my code runs the first time it works exactly as it should until I try to reset for a new game. After I empty the "crystals" div containing my four buttons, I generate four new ones but now they no longer work! How can I empty and repopulate a div with buttons that have click handlers that keep working? I'm new to coding so it's probably something dumb and easy.

I've tried substituting $('#crystals').empty with $('#crystals).html(""), per other articles on stack overflow, but I haven't found any resources specifically dealing with click handlers and the empty() function. I've also moved my functions around so they're inside the document.ready function as suggested by a classmate. I get the distinct impression that I'm asking the wrong questions.


    var growCrystals = function() {
      for (i = 0; i < 4; i++) {
        var crystalButton = $("<button>");
        scoreValue = Math.floor(Math.random() * 12) + 1;
        console.log(scoreValue);
        crystalButton.attr('class' , 'crystal-button');
        crystalButton.attr('score-value' , scoreValue);
        crystalButton.text('button');
        console.log(crystalButton);
        $('#crystals').append(crystalButton);
      }
    }

    var newGame = function() {
      targetNumber = pickTargetNumber();
      totalScore = 0;
      gameOver = false;
      console.log($('#crystals'))
      $('#results').empty();
      $('#crystals').empty();
      console.log($('#crystals'))
      growCrystals();
      console.log($('#crystals'))
      updateGameboard();
      console.log(gameOver);
    }

    // Game
    $('document').ready(function() {
    newGame();

    $('.crystal-button').click(function() {
        totalScore += parseInt($(this).attr('score-value'));
        console.log("pushed ", $(this).attr('score-value'));
        if (gameOver) {
          newGame();
        } else if (totalScore === targetNumber) {
          // You win
          wins++;
          console.log("win ", wins);
          updateGameboard();
          $('#results').text('Player wins! Click any crystal to start a new game!')
          gameOver = true;
        } else if (totalScore > targetNumber) {
          // You lose
          losses++;
          console.log("loss ", losses);
          updateGameboard();
          $('#results').text('Player loses! Click any crystal to start a new game!')
          gameOver = true;
        } else {
          console.log("test loop occured")
          updateGameboard();
        }
      })

    });

    <body class="d-flex flex-column h-100">
        <div class="container">
            <header>...
            </header>

            <section>
                ...
                <div class="row">
                    <!-- <div class="col-md-2"></div> -->
                    <div class="col-md">
                        <div id="crystals"></div>
                    </div>
                    <!-- <div class="col-md-2"></div> -->
                </div>
                ...
            </section>

            <footer class="footer mt-auto py-3">
                ...
            </footer>
        </div>
    </body>   
    ...
    </html>
TSEC
  • 3
  • 3
  • When you remove a button, you remove all the events attached to it. Consider using [event delegation](https://learn.jquery.com/events/event-delegation/) instead. – Tyler Roper May 05 '19 at 23:06
  • Yes that did it. I had no idea you could do that! Thanks very much – TSEC May 05 '19 at 23:20

1 Answers1

1

Use on

Instead of $('.crystal-button').click(function() {

use

$('#crystals').on('click',  '.crystal-button' ,  function() {

This will assign the event handler to items with class .crystal-button in the #crystals element when the child elements are dynamically added. This works via event delegation

Jon P
  • 19,442
  • 8
  • 49
  • 72
  • Yeah this is the solution. And it's a really good one! I had no idea you could do this! Thanks very much! – TSEC May 05 '19 at 23:22