jQuery keyup event rendering same input twice. Generated button not responding to on click event

So I'm currently creating a search app for omdb api using jquery. Right now I have the search bar set up to dynamically update the search results as the user enters in a movie title. Currently I have two problems that I'm stuck on could use some advice on how to fix them. The first problem is whenever I start typing in a movie, sometimes that movie is generated twice and when I press the spacebar, it generates another result of the one before it. For instance if I want to search for the movie Die Hard, When I type in the first letter D, it brings back Tenacious D and the Pick of Destiny twice and then when I finish typing out the word Die, its printed Die Hard 3 times. My other issue is I'm dynamically generating a button on the when data is entered in the search bar. However, I have an on click event set up the to id with that button with a console log of "works" on it, but the button doesnt work, I cant get it to log "works.

My code is listed down below as well as a link to the deployed site so you can see the search area in action as well as the generated button. https://oballematt.github.io/Shoppies/

Any advice would be greatly appreciated! Thanks!

$(document).ready( () => {

    $(".search").on("keyup", () =>{
        const search = $(".search").val()
        const queryUrl = " https://www.omdbapi.com/?t=" + search + "&apikey="
        $.ajax({
            url: queryUrl,
            method: "GET"
        }).then(response => {
            console.log(response)
            $("#movie-title").text(`Results for \"${search}\"`)
            $("#results").append("<ul id='resultsList'>")
            $("#resultsList").append(`<li>${response.Title} (${response.Year}) <button id='nominate'>Nominate</button>`)
            if (response.Response === "False") {
                $("#resultsList").text("")
            }
        });
        
    });

    $("#nominate").on("click", () => {
        console.log("works")
    })

})

1 answer

  • answered 2021-01-11 05:53 Nikhil Patil

    The reason you are getting multiple results is because you are binding the results returned by API every time. The API will return same results with different input (e.g. D will result in Die Hard and so will Die). To avoid this, you need to check if the API returns any unique key against the record (in this case its imdbID) and use it to check if it is already in list to skip.

    But I am not sure why are not you using the s parameter in API to return the list of records directly

    And regarding the button click, its because you are creating the DOM dynamically, so the newly created buttons would not listen to your click event. To address this, you need to add the event every time you create the DOM.

    If you use s param, your code should look like (If there are too many results it won't search) -

    const apiKey = '*******';
    $(document).ready(() => {
    
      $(".search").on("keyup", (e) => {
        e.preventDefault()
        const search = $(".search").val();
        const queryUrl = " https://www.omdbapi.com/?s=" + search + "&apikey=" + apiKey;
        $.ajax({
          url: queryUrl,
          method: "GET"
        }).then(response => {
          $("#movie-title").text(`Results for \"${search}\"`);
          $("#results").html("");
          if (!response.Search || response.Response === "False") {
            return;
          } else {
            const $ul = $("#results").append("<ul");
            for (var item of response.Search) {
              $ul.append(`<li>${item.Title} (${item.Year}) <button>Nominate</button>`);
            }
            $ul.find('li').on('click', () => {
              console.log("works");
            });
          }
        });
    
      });
    })
    body {
      background-color: gray;
    }
    
    .container {
      margin-top: 15%;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
      <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script>
      <link rel="stylesheet" href="style.css">
      <title>The Shoppies</title>
    </head>
    
    <body>
      <div class="container">
        <h1>The Shoppies</h1>
        <div class="row">
          <div class="col-md-12">
            <div class="card">
              <div class="card-body">
                <h5 class="card-title">Movie Title</h5>
                <div class="input-group mb-3">
                  <span class="input-group-text"><i class="bi bi-search"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16">
                      <path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"></path>
                    </svg></i></span>
                  <input type="text" class="form-control search" aria-label="Username" aria-describedby="basic-addon1">
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="row mt-3">
          <div class="col-md-6">
            <div class="card">
              <div id="movie-title" class="card-body"></div>
              <div id="results"></div>
            </div>
          </div>
          <div class="col-md-6">
            <div class="card">
              <div class="card-body">
                <h5 class="card-title">Nominations</h5>
              </div>
            </div>
          </div>
        </div>
      </div>
    </body>