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

Time:08-04

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/[email protected]/dist/css/bootstrap.min.css" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css" />
  <link rel="stylesheet" href="/dist/style.production.css" />
</head>

<body>
  <nav >
    <div >
      <a href="#home" >
        <img src="img/ball.png" width="30" height="24" alt=""  /><span >Pokèdex</span>
      </a>
      <button  type="button" data-bs-toggle="collapse" data-bs-target="#navbarTogglerDemo01" aria-controls="navbarTogglerDemo01" aria-expanded="false" aria-label="Toggle navigation">
          <span ></span>
        </button>
      <div  id="navbarSupportedContent">
        <ul >
          <li >
            <a  aria-current="page" href="#home">Home</a
              >
            </li>
            <li >
              <a  href="#about">About</a>
          </li>
        </ul>
        </li>
        </ul>
        <form  role="search">
          <input  placeholder="Pokemon Name" aria-label="Search" />
          <button  type="submit">
              Search
            </button>
        </form>
      </div>
    </div>
  </nav>

  <p ></p>
  <!-- Pokemon Display -->
  <div >
    <ul ></ul>
  </div>
  <!-- Display Ends Here -->

  <div  id="pokemonModal" tabindex="-1" role="dialog" aria-labelledby="pokemonModalLabel" aria-hidden="true">
    <div  role="document">
      <div >
        <div >
          <h5  id="pokemonModalLabel"></h5>
          <button type="button"  data-dismiss="modal" aria-label="Close" aria-hidden="true"></button>
        </div>
        <!-- Content is dynamically created using jquery -->
        <div ></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/[email protected]/dist/umd/popper.min.js" integrity="sha384-Xe 8cL9oJa6tN/veChSP7q mnSPaj5Bcu9mPX5F5xIGE0DVittaqT5lorf0EI7Vk" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/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>

CodePudding user response:

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/[email protected]/dist/css/bootstrap.min.css" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css" />
  <link rel="stylesheet" href="/dist/style.production.css" />
</head>

<body>
  <nav >
    <div >
      <a href="#home" >
        <img src="img/ball.png" width="30" height="24" alt=""  /><span >Pokèdex</span>
      </a>
      <button  type="button" data-bs-toggle="collapse" data-bs-target="#navbarTogglerDemo01" aria-controls="navbarTogglerDemo01" aria-expanded="false" aria-label="Toggle navigation">
          <span ></span>
        </button>
      <div  id="navbarSupportedContent">
        <ul >
          <li >
            <a  aria-current="page" href="#home">Home</a
              >
            </li>
            <li >
              <a  href="#about">About</a>
          </li>
        </ul>
        </li>
        </ul>
        <form  role="search">
          <input  placeholder="Pokemon Name" aria-label="Search" />
          <button  type="submit">
              Search
            </button>
        </form>
      </div>
    </div>
  </nav>

  <p ></p>
  <!-- Pokemon Display -->
  <div >
    <ul ></ul>
  </div>
  <!-- Display Ends Here -->

  <div  id="pokemonModal" tabindex="-1" role="dialog" aria-labelledby="pokemonModalLabel" aria-hidden="true">
    <div  role="document">
      <div >
        <div >
          <h5  id="pokemonModalLabel"></h5>
          <button type="button"  data-dismiss="modal" aria-label="Close" aria-hidden="true"></button>
        </div>
        <!-- Content is dynamically created using jquery -->
        <div ></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/[email protected]/dist/umd/popper.min.js" integrity="sha384-Xe 8cL9oJa6tN/veChSP7q mnSPaj5Bcu9mPX5F5xIGE0DVittaqT5lorf0EI7Vk" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/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>

  • Related