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?
JavaScript
x
247
247
1
let pokemonRepository = (function() {
2
let pokemonList = [];
3
// API
4
let apiUrl = "https://pokeapi.co/api/v2/pokemon/?limit=150";
5
6
let modalContainer = $(".modal");
7
let modalDialog = $(".modal-dialog");
8
let modalContent = $(".modal-content");
9
let modalBody = $(".modal-body");
10
let modalTitle = $(".modal-title");
11
let modalHeader = $(".modal-header");
12
let modalClose = $(".btn-close");
13
let searchIcon = $(".search-icon");
14
15
let listItemArray = $("li");
16
17
function add(pokemon) {
18
if (
19
typeof pokemon === "object" &&
20
"name" in pokemon &&
21
"detailsUrl" in pokemon
22
) {
23
pokemonList.push(pokemon);
24
} else {
25
console.error("pokemon is not correct");
26
}
27
}
28
29
function getAll() {
30
return pokemonList;
31
}
32
33
// filters through pokemon names
34
function search(pokemonName) {
35
return pokemonList.filter((pokemon) => pokemon.name === pokemonName);
36
}
37
38
// Function adds a list of pokemon
39
function addListItem(pokemon) {
40
let pokemonDisplay = $(".list-group-horizontal");
41
// Creates li element
42
let listItem = $("<li>");
43
listItem.addClass(
44
"list-group-item text-center col-sm-6 col-md-4 border border-secondary bg-image img-fluid"
45
);
46
47
// Creates h1 for Pokemon Name
48
let listTitle = $("<h1>");
49
listTitle.html(`${pokemon.name}`);
50
listTitle.addClass("display-6");
51
52
// Creates div which holds sprites
53
let listImg = $("<div>");
54
loadDetails(pokemon).then(function() {
55
listImg.append(
56
`<img src=${pokemon.imageUrlFront} alt="${pokemon.name} sprite"/>`
57
);
58
});
59
60
let listButton = $("<button>");
61
listButton.text("show More");
62
63
// Added Bootstrap Utility Class
64
listButton.addClass("mp-2 btn btn-secondary");
65
listButton.attr("type", "button");
66
listButton.attr("data-bs-toggle", "modal");
67
listButton.attr("data-bs-toggle", "#pokemonModal");
68
69
listItem.append(listTitle);
70
listItem.append(listImg);
71
listItem.append(listButton);
72
pokemonDisplay.append(listItem);
73
74
buttonEvent(listButton, pokemon);
75
}
76
77
function buttonEvent(listButton, pokemon) {
78
listButton.on("click", () => {
79
showDetails(pokemon);
80
});
81
}
82
83
function showDetails(pokemon) {
84
loadDetails(pokemon).then(() => {
85
// Clears existing content
86
modalContainer.empty();
87
88
modalTitle.addClass("modal-title h5 col-sml-3");
89
90
let pokemonType = {
91
fire: "text-danger",
92
grass: "text-success",
93
water: "text-primary",
94
electric: "text-warning",
95
flying: "text-info",
96
poison: "text-secondary",
97
};
98
99
pokemon.types.forEach((type) =>
100
modalTitle.addClass(pokemonType[type.type.name])
101
);
102
modalTitle.html(`${pokemon.name}`);
103
104
modalBody.html(`
105
Entry: ${pokemon.id}<br>
106
Height: ${pokemon.height}<br>
107
Weight: ${pokemon.weight}<br>
108
Types: ${pokemon.types[0].type.name}`);
109
110
if (pokemon.types.length === 2) {
111
modalBody.innerHTML += `, ${pokemon.types[1].type.name}`;
112
}
113
114
modalBody.innerHTML += `<br>Abilities: ${pokemon.abilities[0]}.ability.name}`;
115
116
if (pokemon.abilities.length === 2) {
117
modalBody.innerHTML += `, ${pokemon.abilities[1]}.ability.name}`;
118
}
119
120
modalBody.append(`<br>
121
<img src=${pokemon.imageUrlFront} alt="${pokemon.name} front sprite">
122
<img src=${pokemon.imageUrlBack} alt="${pokemon.name} back sprite">
123
<br>
124
`);
125
126
modalDialog.append(modalContent);
127
modalContent.append(modalHeader);
128
modalHeader.append(modalTitle);
129
modalHeader.append(modalClose);
130
modalContent.append(modalBody);
131
modalContainer.append(modalDialog);
132
});
133
134
modalContainer.modal("show");
135
}
136
137
// Jquery eventlistener
138
modalClose.on("click", () => {
139
modalContainer.removeClass("fade");
140
modalContainer.show();
141
142
listItemArray[0].lastChild.click();
143
});
144
145
searchIcon.on("click", () => {
146
// fetching .d-flex class in form
147
let bodyHeader = $(".d-flex");
148
// returns the number of child elements
149
if (bodyHeader.lastChild.length === 1) {
150
//creates input element
151
let searchQuery = $("<input>");
152
searchQuery.attr("placeholder", "Pokemon Name");
153
searchQuery.attr("type", "search");
154
searchQuery.attr("aria-label", "search Pokemon Name");
155
searchQuery.addClass("form-control my-3 ps-2 col-sm");
156
157
searchIcon.blur();
158
searchQuery.focus();
159
160
bodyHeader.append(searchQuery);
161
162
searchQuery.on("keydown", (e) => {
163
if (e.key === "Enter") {
164
e.preventDefault();
165
searchQuery.value =
166
searchQuery.value.charAt(0).toUpperCase() +
167
searchQuery.value.slice(1);
168
169
for (let i = 0; i < listItemArray.length; i++) {
170
if (
171
902 > listItemArray[i].lastChild.getBoundingClientRect()["top"] &&
172
listItemArray[i].lastChild.getBoundingClientRect()["top"] > 42
173
) {
174
listItemArray[i].lastChild.click();
175
}
176
}
177
for (let i = 0; i < listItemArray.length; i++) {
178
if (
179
listItemArray[i].innerText.split("n")[0] === searchQuery.value
180
) {
181
setTimeout(function() {
182
listItemArray[i].lastChild.click();
183
}, 5);
184
}
185
}
186
}
187
});
188
}
189
});
190
191
// Fetches data from API
192
function loadList() {
193
return fetch(apiUrl)
194
.then(function(response) {
195
return response.json();
196
})
197
.then(function(json) {
198
json.results.forEach((item) => {
199
let pokemon = {
200
name: item.name.charAt(0).toUpperCase() + item.name.slice(1),
201
detailsUrl: item.url,
202
};
203
add(pokemon);
204
});
205
})
206
.catch(function(error) {
207
console.error(error);
208
});
209
}
210
211
function loadDetails(item) {
212
let url = item.detailsUrl;
213
return fetch(url)
214
.then(function(response) {
215
return response.json();
216
})
217
.then(function(details) {
218
item.imageUrlFront = details.sprites.front_default;
219
item.imageUrlBack = details.sprites.back_default;
220
item.id = details.id;
221
item.height = details.height;
222
item.weight = details.weight;
223
item.types = details.types;
224
item.abilities = details.abilities;
225
})
226
.catch(function(error) {
227
console.error(error);
228
});
229
}
230
231
return {
232
add: add,
233
getAll: getAll,
234
addListItem: addListItem,
235
search: search,
236
showDetails: showDetails,
237
loadList: loadList,
238
loadDetails: loadDetails,
239
buttonEvent: buttonEvent,
240
};
241
})();
242
243
pokemonRepository.loadList().then(function() {
244
pokemonRepository.getAll().forEach(function(pokemon) {
245
pokemonRepository.addListItem(pokemon);
246
});
247
});
JavaScript
1
77
77
1
<!DOCTYPE html>
2
<html lang="en">
3
4
<head>
5
<meta charset="UTF-8" />
6
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
7
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
<meta name="description" content="The Pokédex is a simple encyclopedia of Pokémon and their characteristics." />
9
<link rel="shortcut icon" href="img/favicon.png" type="image/x-icon" />
10
<title>Pokédex App</title>
11
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" />
12
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.3/font/bootstrap-icons.css" />
13
<link rel="stylesheet" href="/dist/style.production.css" />
14
</head>
15
16
<body>
17
<nav class="navbar navbar-expand-lg sticky-top navbar-light bg-light">
18
<div class="container-fluid">
19
<a href="#home" class="navbar-brand">
20
<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>
21
</a>
22
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarTogglerDemo01" aria-controls="navbarTogglerDemo01" aria-expanded="false" aria-label="Toggle navigation">
23
<span class="navbar-toggler-icon"></span>
24
</button>
25
<div class="collapse navbar-collapse" id="navbarSupportedContent">
26
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
27
<li class="nav-item">
28
<a class="nav-link active" aria-current="page" href="#home">Home</a
29
>
30
</li>
31
<li class="nav-item">
32
<a class="nav-link" href="#about">About</a>
33
</li>
34
</ul>
35
</li>
36
</ul>
37
<form class="d-flex" role="search">
38
<input class="form-control me-2" placeholder="Pokemon Name" aria-label="Search" />
39
<button class="btn btn-outline-secondary" type="submit">
40
Search
41
</button>
42
</form>
43
</div>
44
</div>
45
</nav>
46
47
<p class="fw-bold position-absolute top-10 start-50 text-center text-danger"></p>
48
<!-- Pokemon Display -->
49
<div class="container">
50
<ul class="list-group list-group-horizontal flex-fill row mt-4"></ul>
51
</div>
52
<!-- Display Ends Here -->
53
54
<div class="modal fade" id="pokemonModal" tabindex="-1" role="dialog" aria-labelledby="pokemonModalLabel" aria-hidden="true">
55
<div class="modal-dialog pt-5 text-center" role="document">
56
<div class="modal-content">
57
<div class="modal-header">
58
<h5 class="modal-title col-sm-3" id="pokemonModalLabel"></h5>
59
<button type="button" class="btn-close me-3" data-dismiss="modal" aria-label="Close" aria-hidden="true"></button>
60
</div>
61
<!-- Content is dynamically created using jquery -->
62
<div class="modal-body"></div>
63
</div>
64
</div>
65
</div>
66
67
<script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
68
<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>
69
<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>
70
71
<script src="/src/js/scripts.js"></script>
72
73
<script src="/src/js/promise-polyfill.js"></script>
74
<script src="/src/js/fetch-pollyfill.js"></script>
75
</body>
76
77
</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.
JavaScript
1
7
1
modalContainer.on('shown.bs.modal', event => {
2
// Jquery eventlistener
3
modalClose.on("click", () => {
4
modalContainer.modal("hide");
5
});
6
})
7
JavaScript
1
249
249
1
let pokemonRepository = (function() {
2
let pokemonList = [];
3
// API
4
let apiUrl = "https://pokeapi.co/api/v2/pokemon/?limit=150";
5
6
let modalContainer = $(".modal");
7
let modalDialog = $(".modal-dialog");
8
let modalContent = $(".modal-content");
9
let modalBody = $(".modal-body");
10
let modalTitle = $(".modal-title");
11
let modalHeader = $(".modal-header");
12
let modalClose = $(".btn-close");
13
let searchIcon = $(".search-icon");
14
15
let listItemArray = $("li");
16
17
function add(pokemon) {
18
if (
19
typeof pokemon === "object" &&
20
"name" in pokemon &&
21
"detailsUrl" in pokemon
22
) {
23
pokemonList.push(pokemon);
24
} else {
25
console.error("pokemon is not correct");
26
}
27
}
28
29
function getAll() {
30
return pokemonList;
31
}
32
33
// filters through pokemon names
34
function search(pokemonName) {
35
return pokemonList.filter((pokemon) => pokemon.name === pokemonName);
36
}
37
38
// Function adds a list of pokemon
39
function addListItem(pokemon) {
40
let pokemonDisplay = $(".list-group-horizontal");
41
// Creates li element
42
let listItem = $("<li>");
43
listItem.addClass(
44
"list-group-item text-center col-sm-6 col-md-4 border border-secondary bg-image img-fluid"
45
);
46
47
// Creates h1 for Pokemon Name
48
let listTitle = $("<h1>");
49
listTitle.html(`${pokemon.name}`);
50
listTitle.addClass("display-6");
51
52
// Creates div which holds sprites
53
let listImg = $("<div>");
54
loadDetails(pokemon).then(function() {
55
listImg.append(
56
`<img src=${pokemon.imageUrlFront} alt="${pokemon.name} sprite"/>`
57
);
58
});
59
60
let listButton = $("<button>");
61
listButton.text("show More");
62
63
// Added Bootstrap Utility Class
64
listButton.addClass("mp-2 btn btn-secondary");
65
listButton.attr("type", "button");
66
listButton.attr("data-bs-toggle", "modal");
67
listButton.attr("data-bs-toggle", "#pokemonModal");
68
69
listItem.append(listTitle);
70
listItem.append(listImg);
71
listItem.append(listButton);
72
pokemonDisplay.append(listItem);
73
74
buttonEvent(listButton, pokemon);
75
}
76
77
function buttonEvent(listButton, pokemon) {
78
listButton.on("click", () => {
79
showDetails(pokemon);
80
});
81
}
82
83
function showDetails(pokemon) {
84
loadDetails(pokemon).then(() => {
85
// Clears existing content
86
modalContainer.empty();
87
88
modalTitle.addClass("modal-title h5 col-sml-3");
89
90
let pokemonType = {
91
fire: "text-danger",
92
grass: "text-success",
93
water: "text-primary",
94
electric: "text-warning",
95
flying: "text-info",
96
poison: "text-secondary",
97
};
98
99
pokemon.types.forEach((type) =>
100
modalTitle.addClass(pokemonType[type.type.name])
101
);
102
modalTitle.html(`${pokemon.name}`);
103
104
modalBody.html(`
105
Entry: ${pokemon.id}<br>
106
Height: ${pokemon.height}<br>
107
Weight: ${pokemon.weight}<br>
108
Types: ${pokemon.types[0].type.name}`);
109
110
if (pokemon.types.length === 2) {
111
modalBody.innerHTML += `, ${pokemon.types[1].type.name}`;
112
}
113
114
modalBody.innerHTML += `<br>Abilities: ${pokemon.abilities[0]}.ability.name}`;
115
116
if (pokemon.abilities.length === 2) {
117
modalBody.innerHTML += `, ${pokemon.abilities[1]}.ability.name}`;
118
}
119
120
modalBody.append(`<br>
121
<img src=${pokemon.imageUrlFront} alt="${pokemon.name} front sprite">
122
<img src=${pokemon.imageUrlBack} alt="${pokemon.name} back sprite">
123
<br>
124
`);
125
126
modalDialog.append(modalContent);
127
modalContent.append(modalHeader);
128
modalHeader.append(modalTitle);
129
modalHeader.append(modalClose);
130
modalContent.append(modalBody);
131
modalContainer.append(modalDialog);
132
});
133
134
135
136
modalContainer.on('shown.bs.modal', event => {
137
// Jquery eventlistener
138
modalClose.on("click", () => {
139
modalContainer.modal("hide");
140
});
141
142
})
143
modalContainer.modal("show");
144
}
145
146
147
searchIcon.on("click", () => {
148
// fetching .d-flex class in form
149
let bodyHeader = $(".d-flex");
150
// returns the number of child elements
151
if (bodyHeader.lastChild.length === 1) {
152
//creates input element
153
let searchQuery = $("<input>");
154
searchQuery.attr("placeholder", "Pokemon Name");
155
searchQuery.attr("type", "search");
156
searchQuery.attr("aria-label", "search Pokemon Name");
157
searchQuery.addClass("form-control my-3 ps-2 col-sm");
158
159
searchIcon.blur();
160
searchQuery.focus();
161
162
bodyHeader.append(searchQuery);
163
164
searchQuery.on("keydown", (e) => {
165
if (e.key === "Enter") {
166
e.preventDefault();
167
searchQuery.value =
168
searchQuery.value.charAt(0).toUpperCase() +
169
searchQuery.value.slice(1);
170
171
for (let i = 0; i < listItemArray.length; i++) {
172
if (
173
902 > listItemArray[i].lastChild.getBoundingClientRect()["top"] &&
174
listItemArray[i].lastChild.getBoundingClientRect()["top"] > 42
175
) {
176
listItemArray[i].lastChild.click();
177
}
178
}
179
for (let i = 0; i < listItemArray.length; i++) {
180
if (
181
listItemArray[i].innerText.split("n")[0] === searchQuery.value
182
) {
183
setTimeout(function() {
184
listItemArray[i].lastChild.click();
185
}, 5);
186
}
187
}
188
}
189
});
190
}
191
});
192
193
// Fetches data from API
194
function loadList() {
195
return fetch(apiUrl)
196
.then(function(response) {
197
return response.json();
198
})
199
.then(function(json) {
200
json.results.forEach((item) => {
201
let pokemon = {
202
name: item.name.charAt(0).toUpperCase() + item.name.slice(1),
203
detailsUrl: item.url,
204
};
205
add(pokemon);
206
});
207
})
208
.catch(function(error) {
209
console.error(error);
210
});
211
}
212
213
function loadDetails(item) {
214
let url = item.detailsUrl;
215
return fetch(url)
216
.then(function(response) {
217
return response.json();
218
})
219
.then(function(details) {
220
item.imageUrlFront = details.sprites.front_default;
221
item.imageUrlBack = details.sprites.back_default;
222
item.id = details.id;
223
item.height = details.height;
224
item.weight = details.weight;
225
item.types = details.types;
226
item.abilities = details.abilities;
227
})
228
.catch(function(error) {
229
console.error(error);
230
});
231
}
232
233
return {
234
add: add,
235
getAll: getAll,
236
addListItem: addListItem,
237
search: search,
238
showDetails: showDetails,
239
loadList: loadList,
240
loadDetails: loadDetails,
241
buttonEvent: buttonEvent,
242
};
243
})();
244
245
pokemonRepository.loadList().then(function() {
246
pokemonRepository.getAll().forEach(function(pokemon) {
247
pokemonRepository.addListItem(pokemon);
248
});
249
});
JavaScript
1
77
77
1
<!DOCTYPE html>
2
<html lang="en">
3
4
<head>
5
<meta charset="UTF-8" />
6
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
7
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
<meta name="description" content="The Pokédex is a simple encyclopedia of Pokémon and their characteristics." />
9
<link rel="shortcut icon" href="img/favicon.png" type="image/x-icon" />
10
<title>Pokédex App</title>
11
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/css/bootstrap.min.css" />
12
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.3/font/bootstrap-icons.css" />
13
<link rel="stylesheet" href="/dist/style.production.css" />
14
</head>
15
16
<body>
17
<nav class="navbar navbar-expand-lg sticky-top navbar-light bg-light">
18
<div class="container-fluid">
19
<a href="#home" class="navbar-brand">
20
<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>
21
</a>
22
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarTogglerDemo01" aria-controls="navbarTogglerDemo01" aria-expanded="false" aria-label="Toggle navigation">
23
<span class="navbar-toggler-icon"></span>
24
</button>
25
<div class="collapse navbar-collapse" id="navbarSupportedContent">
26
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
27
<li class="nav-item">
28
<a class="nav-link active" aria-current="page" href="#home">Home</a
29
>
30
</li>
31
<li class="nav-item">
32
<a class="nav-link" href="#about">About</a>
33
</li>
34
</ul>
35
</li>
36
</ul>
37
<form class="d-flex" role="search">
38
<input class="form-control me-2" placeholder="Pokemon Name" aria-label="Search" />
39
<button class="btn btn-outline-secondary" type="submit">
40
Search
41
</button>
42
</form>
43
</div>
44
</div>
45
</nav>
46
47
<p class="fw-bold position-absolute top-10 start-50 text-center text-danger"></p>
48
<!-- Pokemon Display -->
49
<div class="container">
50
<ul class="list-group list-group-horizontal flex-fill row mt-4"></ul>
51
</div>
52
<!-- Display Ends Here -->
53
54
<div class="modal fade" id="pokemonModal" tabindex="-1" role="dialog" aria-labelledby="pokemonModalLabel" aria-hidden="true">
55
<div class="modal-dialog pt-5 text-center" role="document">
56
<div class="modal-content">
57
<div class="modal-header">
58
<h5 class="modal-title col-sm-3" id="pokemonModalLabel"></h5>
59
<button type="button" class="btn-close me-3" data-dismiss="modal" aria-label="Close" aria-hidden="true"></button>
60
</div>
61
<!-- Content is dynamically created using jquery -->
62
<div class="modal-body"></div>
63
</div>
64
</div>
65
</div>
66
67
<script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
68
<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>
69
<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>
70
71
<script src="/src/js/scripts.js"></script>
72
73
<script src="/src/js/promise-polyfill.js"></script>
74
<script src="/src/js/fetch-pollyfill.js"></script>
75
</body>
76
77
</html>