Skip to content
Advertisement

Modal close button is not working despite the on() function

whenever I click my “show more” button my modal pops up however when I click my X button on the left corner it doesn’t close like I expect it to. It does respond to clicking outside of the box and the “esc” key.

I believe the issue is happening on modalClose.on() but everything looks fine to me.

Any suggestions as to why this might be happening?

    let pokemonRepository = (function() {
      let pokemonList = [];
      // API
      let apiUrl = "https://pokeapi.co/api/v2/pokemon/?limit=150";

      let modalContainer = $(".modal");
      let modalDialog = $(".modal-dialog");
      let modalContent = $(".modal-content");
      let modalBody = $(".modal-body");
      let modalTitle = $(".modal-title");
      let modalHeader = $(".modal-header");
      let modalClose = $(".btn-close");
      let searchIcon = $(".search-icon");

      let listItemArray = $("li");

      function add(pokemon) {
        if (
          typeof pokemon === "object" &&
          "name" in pokemon &&
          "detailsUrl" in pokemon
        ) {
          pokemonList.push(pokemon);
        } else {
          console.error("pokemon is not correct");
        }
      }

      function getAll() {
        return pokemonList;
      }

      //  filters through pokemon names
      function search(pokemonName) {
        return pokemonList.filter((pokemon) => pokemon.name === pokemonName);
      }

      // Function adds a list of pokemon
      function addListItem(pokemon) {
        let pokemonDisplay = $(".list-group-horizontal");
        // Creates li element
        let listItem = $("<li>");
        listItem.addClass(
          "list-group-item text-center col-sm-6 col-md-4 border border-secondary bg-image img-fluid"
        );

        // Creates h1 for Pokemon Name
        let listTitle = $("<h1>");
        listTitle.html(`${pokemon.name}`);
        listTitle.addClass("display-6");

        // Creates div which holds sprites
        let listImg = $("<div>");
        loadDetails(pokemon).then(function() {
          listImg.append(
            `<img src=${pokemon.imageUrlFront} alt="${pokemon.name} sprite"/>`
          );
        });

        let listButton = $("<button>");
        listButton.text("show More");

        // Added Bootstrap Utility Class
        listButton.addClass("mp-2 btn btn-secondary");
        listButton.attr("type", "button");
        listButton.attr("data-bs-toggle", "modal");
        listButton.attr("data-bs-toggle", "#pokemonModal");

        listItem.append(listTitle);
        listItem.append(listImg);
        listItem.append(listButton);
        pokemonDisplay.append(listItem);

        buttonEvent(listButton, pokemon);
      }

      function buttonEvent(listButton, pokemon) {
        listButton.on("click", () => {
          showDetails(pokemon);
        });
      }

      function showDetails(pokemon) {
        loadDetails(pokemon).then(() => {
          // Clears existing content
          modalContainer.empty();

          modalTitle.addClass("modal-title h5 col-sml-3");

          let pokemonType = {
            fire: "text-danger",
            grass: "text-success",
            water: "text-primary",
            electric: "text-warning",
            flying: "text-info",
            poison: "text-secondary",
          };

          pokemon.types.forEach((type) =>
            modalTitle.addClass(pokemonType[type.type.name])
          );
          modalTitle.html(`${pokemon.name}`);

          modalBody.html(`
            Entry: ${pokemon.id}<br>
            Height: ${pokemon.height}<br>
            Weight: ${pokemon.weight}<br>
            Types: ${pokemon.types[0].type.name}`);

          if (pokemon.types.length === 2) {
            modalBody.innerHTML += `, ${pokemon.types[1].type.name}`;
          }

          modalBody.innerHTML += `<br>Abilities: ${pokemon.abilities[0]}.ability.name}`;

          if (pokemon.abilities.length === 2) {
            modalBody.innerHTML += `, ${pokemon.abilities[1]}.ability.name}`;
          }

          modalBody.append(`<br>
          <img src=${pokemon.imageUrlFront} alt="${pokemon.name} front sprite">
          <img src=${pokemon.imageUrlBack} alt="${pokemon.name} back sprite">
          <br>
          `);

          modalDialog.append(modalContent);
          modalContent.append(modalHeader);
          modalHeader.append(modalTitle);
          modalHeader.append(modalClose);
          modalContent.append(modalBody);
          modalContainer.append(modalDialog);
        });

        modalContainer.modal("show");
      }

      // Jquery eventlistener
      modalClose.on("click", () => {
        modalContainer.removeClass("fade");
        modalContainer.show();

        listItemArray[0].lastChild.click();
      });

      searchIcon.on("click", () => {
        // fetching .d-flex class in form
        let bodyHeader = $(".d-flex");
        // returns the number of child elements
        if (bodyHeader.lastChild.length === 1) {
          //creates input element
          let searchQuery = $("<input>");
          searchQuery.attr("placeholder", "Pokemon Name");
          searchQuery.attr("type", "search");
          searchQuery.attr("aria-label", "search Pokemon Name");
          searchQuery.addClass("form-control my-3 ps-2 col-sm");

          searchIcon.blur();
          searchQuery.focus();

          bodyHeader.append(searchQuery);

          searchQuery.on("keydown", (e) => {
            if (e.key === "Enter") {
              e.preventDefault();
              searchQuery.value =
                searchQuery.value.charAt(0).toUpperCase() +
                searchQuery.value.slice(1);

              for (let i = 0; i < listItemArray.length; i++) {
                if (
                  902 > listItemArray[i].lastChild.getBoundingClientRect()["top"] &&
                  listItemArray[i].lastChild.getBoundingClientRect()["top"] > 42
                ) {
                  listItemArray[i].lastChild.click();
                }
              }
              for (let i = 0; i < listItemArray.length; i++) {
                if (
                  listItemArray[i].innerText.split("n")[0] === searchQuery.value
                ) {
                  setTimeout(function() {
                    listItemArray[i].lastChild.click();
                  }, 5);
                }
              }
            }
          });
        }
      });

      // Fetches data from API
      function loadList() {
        return fetch(apiUrl)
          .then(function(response) {
            return response.json();
          })
          .then(function(json) {
            json.results.forEach((item) => {
              let pokemon = {
                name: item.name.charAt(0).toUpperCase() + item.name.slice(1),
                detailsUrl: item.url,
              };
              add(pokemon);
            });
          })
          .catch(function(error) {
            console.error(error);
          });
      }

      function loadDetails(item) {
        let url = item.detailsUrl;
        return fetch(url)
          .then(function(response) {
            return response.json();
          })
          .then(function(details) {
            item.imageUrlFront = details.sprites.front_default;
            item.imageUrlBack = details.sprites.back_default;
            item.id = details.id;
            item.height = details.height;
            item.weight = details.weight;
            item.types = details.types;
            item.abilities = details.abilities;
          })
          .catch(function(error) {
            console.error(error);
          });
      }

      return {
        add: add,
        getAll: getAll,
        addListItem: addListItem,
        search: search,
        showDetails: showDetails,
        loadList: loadList,
        loadDetails: loadDetails,
        buttonEvent: buttonEvent,
      };
    })();

    pokemonRepository.loadList().then(function() {
      pokemonRepository.getAll().forEach(function(pokemon) {
        pokemonRepository.addListItem(pokemon);
      });
    });
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta name="description" content="The Pokédex is a simple encyclopedia of Pokémon and their characteristics." />
  <link rel="shortcut icon" href="img/favicon.png" type="image/x-icon" />
  <title>Pokédex App</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.3/font/bootstrap-icons.css" />
  <link rel="stylesheet" href="/dist/style.production.css" />
</head>

<body>
  <nav class="navbar navbar-expand-lg sticky-top navbar-light bg-light">
    <div class="container-fluid">
      <a href="#home" class="navbar-brand">
        <img src="img/ball.png" width="30" height="24" alt="" class="d-inline-block align-text-top" /><span class="text-uppercase font-weight-bold text-secondary">Pokèdex</span>
      </a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarTogglerDemo01" aria-controls="navbarTogglerDemo01" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
          <li class="nav-item">
            <a class="nav-link active" aria-current="page" href="#home">Home</a
              >
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#about">About</a>
          </li>
        </ul>
        </li>
        </ul>
        <form class="d-flex" role="search">
          <input class="form-control me-2" placeholder="Pokemon Name" aria-label="Search" />
          <button class="btn btn-outline-secondary" type="submit">
              Search
            </button>
        </form>
      </div>
    </div>
  </nav>

  <p class="fw-bold position-absolute top-10 start-50 text-center text-danger"></p>
  <!-- Pokemon Display -->
  <div class="container">
    <ul class="list-group list-group-horizontal flex-fill row mt-4"></ul>
  </div>
  <!-- Display Ends Here -->

  <div class="modal fade" id="pokemonModal" tabindex="-1" role="dialog" aria-labelledby="pokemonModalLabel" aria-hidden="true">
    <div class="modal-dialog pt-5 text-center" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title col-sm-3" id="pokemonModalLabel"></h5>
          <button type="button" class="btn-close me-3" data-dismiss="modal" aria-label="Close" aria-hidden="true"></button>
        </div>
        <!-- Content is dynamically created using jquery -->
        <div class="modal-body"></div>
      </div>
    </div>
  </div>

  <script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.5/dist/umd/popper.min.js" integrity="sha384-Xe+8cL9oJa6tN/veChSP7q+mnSPaj5Bcu9mPX5F5xIGE0DVittaqT5lorf0EI7Vk" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.min.js" integrity="sha384-ODmDIVzN+pFdexxHEHFBQH3/9/vQ9uori45z4JjnFsRydbmQbmL5t1tQ0culUzyK" crossorigin="anonymous"></script>

  <script src="/src/js/scripts.js"></script>

  <script src="/src/js/promise-polyfill.js"></script>
  <script src="/src/js/fetch-pollyfill.js"></script>
</body>

</html>

Advertisement

Answer

Because for some reason the modal is being reconstructed I assume all the event handlers bootstrap configs for it are gone. So you want to catch click on close, you need to do that after it is shown. This can be done using the event bootstrap provides.

modalContainer.on('shown.bs.modal', event => {
  // Jquery eventlistener
  modalClose.on("click", () => {
    modalContainer.modal("hide");
  });
})

let pokemonRepository = (function() {
  let pokemonList = [];
  // API
  let apiUrl = "https://pokeapi.co/api/v2/pokemon/?limit=150";

  let modalContainer = $(".modal");
  let modalDialog = $(".modal-dialog");
  let modalContent = $(".modal-content");
  let modalBody = $(".modal-body");
  let modalTitle = $(".modal-title");
  let modalHeader = $(".modal-header");
  let modalClose = $(".btn-close");
  let searchIcon = $(".search-icon");

  let listItemArray = $("li");

  function add(pokemon) {
    if (
      typeof pokemon === "object" &&
      "name" in pokemon &&
      "detailsUrl" in pokemon
    ) {
      pokemonList.push(pokemon);
    } else {
      console.error("pokemon is not correct");
    }
  }

  function getAll() {
    return pokemonList;
  }

  //  filters through pokemon names
  function search(pokemonName) {
    return pokemonList.filter((pokemon) => pokemon.name === pokemonName);
  }

  // Function adds a list of pokemon
  function addListItem(pokemon) {
    let pokemonDisplay = $(".list-group-horizontal");
    // Creates li element
    let listItem = $("<li>");
    listItem.addClass(
      "list-group-item text-center col-sm-6 col-md-4 border border-secondary bg-image img-fluid"
    );

    // Creates h1 for Pokemon Name
    let listTitle = $("<h1>");
    listTitle.html(`${pokemon.name}`);
    listTitle.addClass("display-6");

    // Creates div which holds sprites
    let listImg = $("<div>");
    loadDetails(pokemon).then(function() {
      listImg.append(
        `<img src=${pokemon.imageUrlFront} alt="${pokemon.name} sprite"/>`
      );
    });

    let listButton = $("<button>");
    listButton.text("show More");

    // Added Bootstrap Utility Class
    listButton.addClass("mp-2 btn btn-secondary");
    listButton.attr("type", "button");
    listButton.attr("data-bs-toggle", "modal");
    listButton.attr("data-bs-toggle", "#pokemonModal");

    listItem.append(listTitle);
    listItem.append(listImg);
    listItem.append(listButton);
    pokemonDisplay.append(listItem);

    buttonEvent(listButton, pokemon);
  }

  function buttonEvent(listButton, pokemon) {
    listButton.on("click", () => {
      showDetails(pokemon);
    });
  }

  function showDetails(pokemon) {
    loadDetails(pokemon).then(() => {
      // Clears existing content
      modalContainer.empty();

      modalTitle.addClass("modal-title h5 col-sml-3");

      let pokemonType = {
        fire: "text-danger",
        grass: "text-success",
        water: "text-primary",
        electric: "text-warning",
        flying: "text-info",
        poison: "text-secondary",
      };

      pokemon.types.forEach((type) =>
        modalTitle.addClass(pokemonType[type.type.name])
      );
      modalTitle.html(`${pokemon.name}`);

      modalBody.html(`
            Entry: ${pokemon.id}<br>
            Height: ${pokemon.height}<br>
            Weight: ${pokemon.weight}<br>
            Types: ${pokemon.types[0].type.name}`);

      if (pokemon.types.length === 2) {
        modalBody.innerHTML += `, ${pokemon.types[1].type.name}`;
      }

      modalBody.innerHTML += `<br>Abilities: ${pokemon.abilities[0]}.ability.name}`;

      if (pokemon.abilities.length === 2) {
        modalBody.innerHTML += `, ${pokemon.abilities[1]}.ability.name}`;
      }

      modalBody.append(`<br>
          <img src=${pokemon.imageUrlFront} alt="${pokemon.name} front sprite">
          <img src=${pokemon.imageUrlBack} alt="${pokemon.name} back sprite">
          <br>
          `);

      modalDialog.append(modalContent);
      modalContent.append(modalHeader);
      modalHeader.append(modalTitle);
      modalHeader.append(modalClose);
      modalContent.append(modalBody);
      modalContainer.append(modalDialog);
    });



    modalContainer.on('shown.bs.modal', event => {
      // Jquery eventlistener
      modalClose.on("click", () => {
        modalContainer.modal("hide");
      });

    })
    modalContainer.modal("show");
  }


  searchIcon.on("click", () => {
    // fetching .d-flex class in form
    let bodyHeader = $(".d-flex");
    // returns the number of child elements
    if (bodyHeader.lastChild.length === 1) {
      //creates input element
      let searchQuery = $("<input>");
      searchQuery.attr("placeholder", "Pokemon Name");
      searchQuery.attr("type", "search");
      searchQuery.attr("aria-label", "search Pokemon Name");
      searchQuery.addClass("form-control my-3 ps-2 col-sm");

      searchIcon.blur();
      searchQuery.focus();

      bodyHeader.append(searchQuery);

      searchQuery.on("keydown", (e) => {
        if (e.key === "Enter") {
          e.preventDefault();
          searchQuery.value =
            searchQuery.value.charAt(0).toUpperCase() +
            searchQuery.value.slice(1);

          for (let i = 0; i < listItemArray.length; i++) {
            if (
              902 > listItemArray[i].lastChild.getBoundingClientRect()["top"] &&
              listItemArray[i].lastChild.getBoundingClientRect()["top"] > 42
            ) {
              listItemArray[i].lastChild.click();
            }
          }
          for (let i = 0; i < listItemArray.length; i++) {
            if (
              listItemArray[i].innerText.split("n")[0] === searchQuery.value
            ) {
              setTimeout(function() {
                listItemArray[i].lastChild.click();
              }, 5);
            }
          }
        }
      });
    }
  });

  // Fetches data from API
  function loadList() {
    return fetch(apiUrl)
      .then(function(response) {
        return response.json();
      })
      .then(function(json) {
        json.results.forEach((item) => {
          let pokemon = {
            name: item.name.charAt(0).toUpperCase() + item.name.slice(1),
            detailsUrl: item.url,
          };
          add(pokemon);
        });
      })
      .catch(function(error) {
        console.error(error);
      });
  }

  function loadDetails(item) {
    let url = item.detailsUrl;
    return fetch(url)
      .then(function(response) {
        return response.json();
      })
      .then(function(details) {
        item.imageUrlFront = details.sprites.front_default;
        item.imageUrlBack = details.sprites.back_default;
        item.id = details.id;
        item.height = details.height;
        item.weight = details.weight;
        item.types = details.types;
        item.abilities = details.abilities;
      })
      .catch(function(error) {
        console.error(error);
      });
  }

  return {
    add: add,
    getAll: getAll,
    addListItem: addListItem,
    search: search,
    showDetails: showDetails,
    loadList: loadList,
    loadDetails: loadDetails,
    buttonEvent: buttonEvent,
  };
})();

pokemonRepository.loadList().then(function() {
  pokemonRepository.getAll().forEach(function(pokemon) {
    pokemonRepository.addListItem(pokemon);
  });
});
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta name="description" content="The Pokédex is a simple encyclopedia of Pokémon and their characteristics." />
  <link rel="shortcut icon" href="img/favicon.png" type="image/x-icon" />
  <title>Pokédex App</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.3/font/bootstrap-icons.css" />
  <link rel="stylesheet" href="/dist/style.production.css" />
</head>

<body>
  <nav class="navbar navbar-expand-lg sticky-top navbar-light bg-light">
    <div class="container-fluid">
      <a href="#home" class="navbar-brand">
        <img src="img/ball.png" width="30" height="24" alt="" class="d-inline-block align-text-top" /><span class="text-uppercase font-weight-bold text-secondary">Pokèdex</span>
      </a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarTogglerDemo01" aria-controls="navbarTogglerDemo01" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
      <div class="collapse navbar-collapse" id="navbarSupportedContent">
        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
          <li class="nav-item">
            <a class="nav-link active" aria-current="page" href="#home">Home</a
              >
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#about">About</a>
          </li>
        </ul>
        </li>
        </ul>
        <form class="d-flex" role="search">
          <input class="form-control me-2" placeholder="Pokemon Name" aria-label="Search" />
          <button class="btn btn-outline-secondary" type="submit">
              Search
            </button>
        </form>
      </div>
    </div>
  </nav>

  <p class="fw-bold position-absolute top-10 start-50 text-center text-danger"></p>
  <!-- Pokemon Display -->
  <div class="container">
    <ul class="list-group list-group-horizontal flex-fill row mt-4"></ul>
  </div>
  <!-- Display Ends Here -->

  <div class="modal fade" id="pokemonModal" tabindex="-1" role="dialog" aria-labelledby="pokemonModalLabel" aria-hidden="true">
    <div class="modal-dialog pt-5 text-center" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title col-sm-3" id="pokemonModalLabel"></h5>
          <button type="button" class="btn-close me-3" data-dismiss="modal" aria-label="Close" aria-hidden="true"></button>
        </div>
        <!-- Content is dynamically created using jquery -->
        <div class="modal-body"></div>
      </div>
    </div>
  </div>

  <script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.5/dist/umd/popper.min.js" integrity="sha384-Xe+8cL9oJa6tN/veChSP7q+mnSPaj5Bcu9mPX5F5xIGE0DVittaqT5lorf0EI7Vk" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.min.js" integrity="sha384-ODmDIVzN+pFdexxHEHFBQH3/9/vQ9uori45z4JjnFsRydbmQbmL5t1tQ0culUzyK" crossorigin="anonymous"></script>

  <script src="/src/js/scripts.js"></script>

  <script src="/src/js/promise-polyfill.js"></script>
  <script src="/src/js/fetch-pollyfill.js"></script>
</body>

</html>
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement