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

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>

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>

Related

need help understanding why searchQuery.value is undefined

so i'm currently trying to build search icon on the header clickable where you're able to search for, in this case, pokemon names, however i keep getting a console error
searchQuery.value undefined
Not sure why because the code looks valid.
Also, when you click on the search icon the icon goes above it and once you hit submit on the input it duplicates. I'm sure it's all connected the bug.
No sure why this is happening and would greatly appreciate any advice to fix this.
let pokemonRepository = (function() {
let pokemonList = [];
// API
let apiUrl = "https://pokeapi.co/api/v2/pokemon/?limit=150";
let searchIcon = $(".btn-outline-secondary");
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 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");
}
modalContainer.on("shown.bs.modal", () => {
// Jquery eventlistener
modalClose.on("click", () => {
modalContainer.removeClass("fade");
modalContainer.modal("hide");
listItemArray[0].children().click();
});
});
searchIcon.on("click", () => {
// fetching .d-flex class in form
let bodyHeader = $(".d-flex");
// returns the number of child elements
if (bodyHeader.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].children().last().getBoundingClientRect()[
"top"
] &&
listItemArray[i].children().last().getBoundingClientRect()[
"top"
] > 42
) {
listItemArray[i].children().last().click();
}
}
for (let i = 0; i < listItemArray.length; i++) {
if (listItemArray[i].text().split("\n")[0] === searchQuery.value) {
setTimeout(function() {
listItemArray[i].children().last().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 row" role="search">
<!-- <input
class="form-control me-2"
placeholder="Pokemon Name"
aria-label="Search"
/> -->
<button class="btn btn-outline-secondary" type="submit">
<i class="bi bi-search"></i>
</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>
Since searchQuery is a jQuery object, you need to use its .val() method to set and get the value. So change.
searchQuery.value =
searchQuery.value.charAt(0).toUpperCase() +
searchQuery.value.slice(1);
to
searchQuery.val((i, value) => value[0].toUpperCase() + value.slice(1));

How do i fix the result without reloading the site?

Whenever I am writing apple or samsung, It is showing results, but if I don't refresh the page for the second time, it gives me error. However, If I reload the website, then it is showing me the results of samsung or oppo or whatever. Can you please tell me where I made the mistake ? I am attaching the HTML and JS below :
// error handle
const displayHandle = (direction, id) => {
const errorMessage = document.getElementById(id);
errorMessage.style.display = direction;
}
// clear previous result
const clearSearchResult = (direction) => {
const searchResult = document.getElementById(direction);
searchResult.innerHTML = '';
}
// details button action form
const allDetails = (id) => {
// console.log(id)
fetch(`https://openapi.programming-hero.com/api/phone/${id}`)
.then(response => response.json())
.then(data => {
const sensorName = data.data.mainFeatures.sensors;
let storeSensorName = '';
for (const sensor of sensorName) {
storeSensorName = `${storeSensorName} ${sensor}, `
}
const mobileDetails = document.getElementById('show-details');
mobileDetails.innerHTML = `
<div class=" row row-cols-1 row-cols-md-3 g-4">
<div class="col">
<div class="card">
<img src=${data.data.image} class="card-img-top w-50 h-50" alt="...">
<div id="details-body" class="card-body">
<h5 class="card-title">Brand: ${data.data.brand}</h5>
<p class="card-text">Storage: ${data.data.mainFeatures.storage}</p>
<p class="card-text">ChipSet: ${data.data.mainFeatures.chipSet}</p>
<p class="card-text">DisplaySize: ${data.data.mainFeatures.displaySize}</p>
<p class="card-text">Sensors : ${storeSensorName}</p>
</div>
</div>
</div>
</div>
`;
// inject release Date
const container = document.getElementById('details-body');
const p = document.createElement('p');
if (data.data.releaseDate) {
p.innerText = `Release Information:${data.data.releaseDate}`;
container.appendChild(p);
} else {
p.innerText = `Release Information Not Found`;
container.appendChild(p);
}
});
}
//search button action form
document.getElementById('search-btn').addEventListener('click', function() {
clearSearchResult('show-details');
clearSearchResult('show-mobile');
displayHandle('none', 'error-message');
displayHandle('none', 'show-all-Button')
// get search field
const searchBox = document.getElementById('search-box');
const searchData = searchBox.value;
fetch(`https://openapi.programming-hero.com/api/phones?search=${searchData}`)
.then(res => res.json())
.then(data => {
if (data.data.length != 0) {
displayMobile(data.data)
} else {
displayHandle('block', 'error-message');
}
})
// clear search field
searchBox.value = ' ';
})
const displayMobile = (mobiles) => {
// console.log(phones);
const showMobile = document.getElementById('show-mobile');
let count = 0;
for (const mobile of mobiles) {
if (count < 20) {
const div = document.createElement('div');
div.classList.add("col");
div.innerHTML = `
<div class="card d-flex align-items-center">
<img src=${mobile.image} class="card-img-top w-50 h-50" alt="...">
<div class="card-body">
<h5 class="card-title">Model : ${mobile.phone_name}</h5>
<p class="card-text">Brand : ${mobile.brand}</p>
<button class="card-button" onclick="allDetails('${mobile.slug}')">Details</button>
</div>
</div>
`;
showMobile.appendChild(div);
} else {
displayHandle('block', 'show-all-Button');
}
count++;
}
}
<!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">
<title>Document</title>
<!-- connection with bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<style>
.display-handle {
display: none;
color: rgb(231, 49, 49);
}
.card-button {
color: white;
background-color: brown;
border-radius: 10px;
}
</style>
</head>
<body>
<!-- search box section
----------------->
<section class="container w-75 mx-auto pt-5">
<h5 id="error-message" class="display-handle text-center">Not found..! Press authentic data...</h5>
<h3 class="text-center bg-dark text-white">Mobile Maya</h3>
<div class="input-group mb-3">
<input id="search-box" type="text" class="form-control" placeholder="Enter your desired mobile " aria-label="" aria-describedby="button-addon2">
<button class="btn btn-success" type="button" id="search-btn">Search</button>
</div>
</section>
<!-- display products details -->
<section id="show-details" class="container">
<!-- inject details here -->
</section>
<!-- search result display section
---------------------------------->
<section class="container pt-5">
<div id="show-mobile" class=" row row-cols-1 row-cols-md-3 g-4">
</div>
</section>
<!-- show all button -->
<section class="container">
<div class="d-flex justify-content-center">
<button style="color: white; background-color:tomato; border-radius: 8px;" id="show-all-Button" class="display-handle" type="button" class="btn btn-primary">Show All</button>
</div>
</section>
<!-- connection with js
----------- -->
<script src="js/app.js"></script>
<!-- connection with bootstrap script -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
</body>
</html>
It is because of this line, you don't really clear the search field :
// clear search field
searchBox.value = ' ';
You should either assign the empty string value '' or call the method trim() on searchData.

How do I get the bootstrap modal to work in my code?

Hey there I am just have trouble bringing up a modal working with bootstrap. Theoretically I have a list of pokemon that I fetched from another website. Then each pokemon is supposed to act as a button to where i can then click on and receive more information about. I would appreciate some help as I am pretty lost.
Thanks
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Simple JS App</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.3.1/dist/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" type="text/css" href="css/styles.css">
</head>
<body>
<header class="page-header">
<nav class="navbar fixed-top navbar-expand-sm navbar-light bg-light">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-target="#myModal" data-toggle="modal" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Features</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Pricing</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
</li>
</ul>
</div>
</nav>
</header>
<h1>Pokedex</h1>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModal" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="myModalLabel">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" data-target="#myModal" data-toggle="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<ul class="list-group"></ul>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.14.7/dist/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#4.3.1/dist/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="js/scripts.js"></script>
</body>
</html>
JS
let pokemonRepository = (function () {
let pokemonList = [];
let apiUrl = 'https://pokeapi.co/api/v2/pokemon/?limit=150';
function add(pokemon) {
pokemonList.push(pokemon);
}
function getAll() {
return pokemonList;
}
function addListItem(pokemon) {
let pokemonList = document.querySelector('.list-group');
let listPokemon = document.createElement('li');
listPokemon.classList.add('group-list-item');
let button = document.createElement('button');
button.innerText = pokemon.name;
button.classList.add('btn');
pokemonList.appendChild(listPokemon);
listPokemon.appendChild(button);
button.addEventListener('click', function(event) {
showDetails(pokemon);
});
}
function loadList() {
return fetch(apiUrl).then(function (response) {
return response.json();
}).then(function (json) {
json.results.forEach(function (item) {
let pokemon = {
name: item.name,
detailsUrl: item.url
};
add(pokemon);
console.log(pokemon);
});
}).catch(function (e) {
console.error(e);
});
}
function loadDetails(item) {
let url = item.detailsUrl;
return fetch(url).then(function (response) {
return response.json();
}).then(function (details) {
// Now we add the details to the item
item.imageUrl = details.sprites.front_default;
item.height = details.height;
item.types = details.types;
}).catch(function (e) {
console.error(e);
});
}
function showDetails(pokemon) {
loadDetails(pokemon).then(function () {
showModal(pokemon);
});
};
function showModal(item) {
let modalContainer = document.querySelector('#myModal');
modalContainer.classList.add('is-visible');
// Clear all existing modal content
modalContainer.innerHTML = '';
modalContainer.addEventListener('click', (e) => {
// Since this is also triggered when clicking INSIDE the modal
// We only want to close if the user clicks directly on the overlay
let target = e.target;
if (target === modalContainer) {
hideModal();
}
});
let modal = document.createElement('div');
modal.classList.add('modal');
// Add the new modal content
let closeButtonElement = document.createElement('button');
closeButtonElement.classList.add('modal-close');
closeButtonElement.innerText = 'Close';
closeButtonElement.addEventListener('click', hideModal);
let titleElement = document.createElement('h1');
titleElement.innerText = item.name + (': ') + ('height = ') + item.height;
let container = document.querySelector('#image-container');
let myImage = document.createElement('img');
myImage.src = item.imageUrl;
modal.appendChild(closeButtonElement);
modal.appendChild(titleElement);
modalContainer.appendChild(modal);
modal.appendChild(myImage);
}
function hideModal() {
let modalContainer = document.querySelector('#myModal');
modalContainer.classList.remove('is-visible');
}
window.addEventListener('keydown', (e) => {
let modalContainer = document.querySelector('#myModal');
if (e.key === 'Escape' && modalContainer.classList.contains('is-visible')) {
hideModal();
}
});
return {
add: add,
getAll: getAll,
addListItem: addListItem,
loadList: loadList,
loadDetails: loadDetails,
showDetails: showDetails
};
})();
pokemonRepository.loadList().then(function () {
pokemonRepository.getAll().forEach(function (pokemon) {
pokemonRepository.addListItem(pokemon);
});
});
1 - There is few errors in your code. To open a bootstrap modal there is a method:
$('#myModal').modal('show');
2 - Then you cleaned the structure of the modal with the innerHTML instead of the modal-body and you are trying to recreate all the elements dynamically.
What you can do is just replacing the content of the modal body or do not forget to re-create every element of the modal which is not what you did.
Here is a working example:
https://codepen.io/alxtaz/pen/WNXYOrd

Arrange todo items using drag and drop

I'm trying to create a todo list then use drag and drop to arrange it as I want. I have a dummy data (list items) which I can arrange as I want. the problem I am having is any new todo I add to the list item can not be dragged or rearrange.
here is my code below
var form = document.getElementById('addForm');
var itemList = document.getElementById('items');
form.addEventListener('submit', addTodo);
itemList.addEventListener('click', removeItem)
function addTodo(e) {
e.preventDefault()
// get input value
var newTodo = document.getElementById('todo');
// create new li element
var li = document.createElement('li')
//add class draggable property
li.className = 'draggable';
li.draggable = true
// add textnode with input value
li.appendChild(document.createTextNode(newTodo.value))
// delete button
var delBtn = document.createElement('button')
delBtn.className = 'btn btn-danger btn-sm float-right del';
delBtn.appendChild(document.createTextNode('X'))
li.appendChild(delBtn)
itemList.appendChild(li)
newTodo.value = ""
}
function removeItem(e) {
if (e.target.classList.contains('del')) {
if (confirm('Are you sure?')) {
var li = e.target.parentElement
itemList.removeChild(li)
}
}
}
const draggables = document.querySelectorAll('.draggable')
draggables.forEach(draggable => {
draggable.addEventListener('dragstart', () => {
draggable.classList.add('dragging')
})
draggable.addEventListener('dragend', () => {
draggable.classList.remove('dragging')
})
})
itemList.addEventListener('dragover', (e) => {
e.preventDefault()
const draggable = document.querySelector('.dragging')
const afterElement = getDragAfterElement(draggable, e.clientY)
console.log(afterElement);
if (afterElement == null) {
itemList.appendChild(draggable)
} else {
itemList.insertBefore(draggable, afterElement)
}
})
function getDragAfterElement(draggables, y) {
const draggableElements = [...document.querySelectorAll('.draggable:not(.dragging)')]
console.log('Dragable', draggableElements);
return draggableElements.reduce((closest, child) => {
const box = child.getBoundingClientRect()
const offset = y - box.top - box.height / 2
if (offset < 0 && offset > closest.offset) {
return {
offset: offset,
element: child
}
} else {
return closest
}
}, {
offset: Number.NEGATIVE_INFINITY
}).element
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Todo task</title>
<!-- Font Awesome -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.2/css/all.css">
<!-- Google Fonts -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap">
<!-- Bootstrap core CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet">
<!-- Material Design Bootstrap -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.19.1/css/mdb.min.css" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container mt-2">
<div class="row justify-content-center">
<div class="col-md-8">
<h1>Todo Task</h1>
<div class="card">
<div class="card-header bg-grey">
<h4>What Todo</h4>
</div>
<div class="card-body">
<form action="" id="addForm">
<div class="form-group mt-2 pl-5">
<label for="">Title of Task</label>
<input type="text" id="todo" placeholder="Enter todo..." class="form-control">
</div>
<button type="submit" id="submit" class="btn btn-primary btn-sm">Submit</button>
</form>
</div>
</div>
<div class="jumb mt-4">
<h2>Todo Lists</h2>
<ul class="list-group" id="items">
<li class="draggable" draggable="true">Item 1 <button class="btn btn-danger btn-sm float-right del">X</button></li>
<li class="draggable" draggable="true">Item 2 <button class="btn btn-danger btn-sm float-right del">X</button></li>
<li class="draggable" draggable="true">Item 3 <button class="btn btn-danger btn-sm float-right del">X</button></li>
</ul>
</div>
</div>
</div>
</div>
<!-- JQuery -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- Bootstrap tooltips -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.4/umd/popper.min.js"></script>
<!-- Bootstrap core JavaScript -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.0/js/bootstrap.min.js"></script>
<!-- MDB core JavaScript -->
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mdbootstrap/4.19.1/js/mdb.min.js"></script>
<script src="app.js"></script>
</body>
</html>
If I understand it correctly you are attaching some events to every item on the list to allow the drag&drop functionality.
The new elements don't have those events attached to them, though. You need to watch for new elements and initialize the drag&drop functionality for them too.
NOTICE: Heretic Monkey has linked to a more comprehensive answer.
You need to warp this piece of into function
const draggables = document.querySelectorAll('.draggable')
draggables.forEach(draggable => {
draggable.addEventListener('dragstart', () => {
draggable.classList.add('dragging')
})
draggable.addEventListener('dragend', () => {
draggable.classList.remove('dragging')
})
})
To
function enableDragDrop() {
const draggables = document.querySelectorAll('.draggable')
draggables.forEach(draggable => {
draggable.addEventListener('dragstart', () => {
draggable.classList.add('dragging')
})
draggable.addEventListener('dragend', () => {
draggable.classList.remove('dragging')
})
})
}
and call the function in addTodo(e) that is called event binding
function addTodo(e) {
....
enableDragDrop();
}
also, call the function on page load show it should bind the drag events by default
....
var form = document.getElementById('addForm');
var itemList = document.getElementById('items');
form.addEventListener('submit', addTodo);
itemList.addEventListener('click', removeItem)
enableDragDrop();
Complete JS.
var form = document.getElementById('addForm');
var itemList = document.getElementById('items');
form.addEventListener('submit', addTodo);
itemList.addEventListener('click', removeItem)
enableDragDrop();
function addTodo(e) {
e.preventDefault()
// get input value
var newTodo = document.getElementById('todo');
// create new li element
var li = document.createElement('li')
//add class draggable property
li.className = 'draggable';
li.draggable = true
// add textnode with input value
li.appendChild(document.createTextNode(newTodo.value))
// delete button
var delBtn = document.createElement('button')
delBtn.className = 'btn btn-danger btn-sm float-right del';
delBtn.appendChild(document.createTextNode('X'))
li.appendChild(delBtn)
itemList.appendChild(li)
newTodo.value = "";
enableDragDrop();
}
function removeItem(e) {
if (e.target.classList.contains('del')) {
if (confirm('Are you sure?')) {
var li = e.target.parentElement
itemList.removeChild(li)
}
}
}
function enableDragDrop() {
const draggables = document.querySelectorAll('.draggable')
draggables.forEach(draggable => {
draggable.addEventListener('dragstart', () => {
draggable.classList.add('dragging')
})
draggable.addEventListener('dragend', () => {
draggable.classList.remove('dragging')
})
})
}
itemList.addEventListener('dragover', (e) => {
e.preventDefault()
const draggable = document.querySelector('.dragging')
const afterElement = getDragAfterElement(draggable, e.clientY)
console.log(afterElement);
if (afterElement == null) {
itemList.appendChild(draggable)
} else {
itemList.insertBefore(draggable, afterElement)
}
})
function getDragAfterElement(draggables, y) {
const draggableElements = [...document.querySelectorAll('.draggable:not(.dragging)')]
console.log('Dragable', draggableElements);
return draggableElements.reduce((closest, child) => {
const box = child.getBoundingClientRect()
const offset = y - box.top - box.height / 2
if (offset < 0 && offset > closest.offset) {
return {offset: offset, element: child}
} else {
return closest
}
}, {offset: Number.NEGATIVE_INFINITY}).element
}

Unable to access the DOM which I passed as a string. How to do it by using external function as I defined in the code?

I want to add an event to the "Important" link i.e. When One user clicks the "Important" link, the corresponding card color should be changed and saved in the localstorage but, when I am accessing that DOM file which I passed as a string, I am unable to do it. For e.g. - I can't access to document.getElementsByClassName("noteCard") in function markNotes(index). But at the same time
console.log("Color is not applied") executes successfully. If I am adding document.body.style.backgroundColor = "lightblue"; then also body color changes accordingly, but the I want to change the background color of the card with class "noteCard" only. I am really stuck with it.
Below is my HTML code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Magic Notes</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<link rel="stylesheet" href="Customstyle.css">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar navbar-dark bg-dark">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-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="navbarTogglerDemo01">
<a class="navbar-brand" href="#">Magic Notes</a>
<ul class="navbar-nav mr-auto mt-2 mt-lg-0">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="https://www.facebook.com/balabhadra.chand/" target="_blank">About me</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" id="searchTitle" type="search" placeholder="Search by title" aria-label="Search">
</form>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" id="searchTxt" type="search" placeholder="Search text" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0 " id="searchBtn" type="submit">Search</button>
</form>
</div>
</nav>
<h1 class="heading">It's all about magic !!!</h1>
<div class="card" style="width: 1000px;">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text">Add a title to your note</textarea></span>
</div>
<textarea class="form-control" id="addTitle" aria-label="With textarea"></textarea>
</div>
<div class="card-body">
<form>
<div class="form-group">
<label for="exampleFormControlTextarea1">Write your Note</label>
<textarea class="form-control" id="addTxt" rows="3"></textarea>
</div>
</form>
<button class="btn btn-primary" id="addBtn">ADD NOTE</button>
</div>
</div>
<hr>
<h5>Your Notes</h5>
<hr>
<div id="notes" class="row container-fluid"></div>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js#1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
<script src="myscript.js"></script>
</body>
Here is my JavaScript code
console.log('MagicNotes')
showNotes();
let addBtn = document.getElementById("addBtn");
addBtn.addEventListener("click", function(e) {
let addTxt = document.getElementById("addTxt");
let addTitle = document.getElementById("addTitle");
let notes = localStorage.getItem("notes");
if (notes != null) {
notesObj = JSON.parse(notes);
} else {
notesObj = [];
}
let myObj = {
title: addTitle.value,
text: addTxt.value
}
notesObj.push(myObj)
localStorage.setItem("notes", JSON.stringify(notesObj));
addTxt.value = "";
addTitle.value = "";
showNotes();
});
function showNotes() {
let notes = localStorage.getItem("notes");
if (notes != null) {
notesObj = JSON.parse(notes);
} else {
notesObj = [];
}
let html = "";
notesObj.forEach(function(element, index) {
html += `<div class="noteCard card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">Title: ${element.title}</h5>
<p class="card-text">${element.text}</p>
<a href="#" id="${index}"onclick="deleteNotes(this.id)" class="card-link" >Delete Note</a>
Important
</div>
</div>`;
});
let notesElem = document.getElementById("notes");
if (notesObj.length != 0) {
notesElem.innerHTML = html;
} else {
notesElem.innerHTML = `Please add a note by clicking "ADD NOTE"`;
}
}
function deleteNotes(index) {
let notes = localStorage.getItem("notes");
if (notes != null) {
notesObj = JSON.parse(notes);
} else {
notesObj = [];
}
notesObj.splice(index, 1);
localStorage.setItem("notes", JSON.stringify(notesObj));
showNotes();
}
function markNotes(index) {
let notes = localStorage.getItem("notes");
if (notes != null) {
notesObj = JSON.parse(notes);
} else {
notesObj = [];
}
document.getElementsByClassName("noteCard").style.color = "lightblue";
console.log("Color is not applied")
localStorage.setItem("notes", JSON.stringify(notesObj));
showNotes();
}
let searchText = document.getElementById('searchTxt');
searchText.addEventListener("input", function(txt) {
let inputVal = searchText.value.toLowerCase();
// console.log('Input event fired!', inputVal);
let noteCards = document.getElementsByClassName('noteCard');
Array.from(noteCards).forEach(function(element) {
let cardTxt = element.getElementsByTagName("p")[0].innerText;
if (cardTxt.includes(inputVal)) {
element.style.display = "block";
} else {
element.style.display = "none";
}
// console.log(cardTxt);
})
})
let searchTitle = document.getElementById('searchTitle');
searchTitle.addEventListener("input", function(title) {
let inputValTitle = searchTitle.value.toLowerCase();
let noteCardsTitle = document.getElementsByClassName('noteCard');
Array.from(noteCardsTitle).forEach(function(element) {
let cardTitle = element.getElementsByTagName("h5")[0].innerText;
if (cardTitle.includes(inputValTitle)) {
element.style.display = "block";
} else {
element.style.display = "none";
}
// console.log(cardTitle);
})
})
You were missing index while fetching element inside markNotes:
function markNotes(index) {
let notes = localStorage.getItem("notes");
if (notes != null) {
notesObj = JSON.parse(notes);
} else {
notesObj = [];
}
let noteCard = document.getElementsByClassName("noteCard")[index];
noteCard.style.color = "lightblue";
console.log("Color is applied")
localStorage.setItem("notes", JSON.stringify(notesObj));
//showNotes(); you don't need to add this again
}
complete working code fiddle link

Categories