Hey everyone I'm trying to use the filter method on the Pokémon api data, but I'm not understanding what I'm doing wrong. What I'm trying to accomplish is when a user clicks the filter buttons, the type of Pokémon is displayed.. for example..(user clicks fire button, fire Pokémon are displayed),
I tried to use the .pokeContainer div to display when user clicks the button but that's not working, any help would be greatly appreciated. Thank you
//Function to fetch 151 pokemon
function fetchPokemon() {
let pokemonArr = [];
// const url = `https://pokeapi.co/api/v2/pokemon?${i}`
// const url = 'Charizard, Mewtwo';
for (let i = 1; i <= 150; i++) {
const url = `https://pokeapi.co/api/v2/pokemon/${i}`
pokemonArr.push(fetch(url).then(data => data.json()))
// pokemonArr.push(url);
}
// console.log(pokemonArr)
//Promise.all to iterate over array and return a single array/Promise
// Promise.all(pokemonArr).then(data => console.log(data))
Promise.all(pokemonArr).then((results) => {
const pokemon = results.map((result) => ({
name: result.name,
id: result.id,
image: result.sprites['front_default'],
type: result.types.map((type) => type.type.name),
}))
createPokeCard(pokemon)
})
}
//Create pokemon div and display pokemon
const createPokeCard = (pokemon) => {
const allPokemonContainer = document.querySelector('.allPokemonContainer');
const pokemonInnerHTML = pokemon.map((pokemon) =>
`<div class="pokeContainer">
<image src="${pokemon.image}">
<h2 class="card-title">${pokemon.id}. ${pokemon.name}</h2>
<p>${pokemon.type}</p>
</div>`
)
allPokemonContainer.innerHTML = pokemonInnerHTML;
// typeFilter(pokemon)
searchFilter()
typeFilter(pokemon)
}
//Search filter for displaying Pokemon
const searchFilter = () => {
const searchBar = document.querySelector('.search-bar');
const pokeContainer = document.querySelectorAll('.pokeContainer');
searchBar.addEventListener('keyup', (event) => {
let value = event.target.value.toLowerCase();
console.log(value)
pokeContainer.forEach((container) => {
if (container.querySelector('h2').textContent.toLowerCase().includes(value)) {
container.style.display = 'block'
} else {
container.style.display = 'none'
}
})
// console.log('Hello')
// console.log(search);
})
}
// a filter for iterating through pokemon types
function typeFilter(pokemon) {
const pokeContainer = document.querySelectorAll('.pokeContainer');
const filterBtn = document.querySelectorAll('.filter-btn');
filterBtn.forEach(function(btn) {
btn.addEventListener('click', (e) => {
// console.log(btn);
// console.log(btn.innerText);
let type = e.currentTarget.innerText;
console.log(type);
// console.log(pokemon)
pokeContainer.forEach((container) => {
if (type === btn.innerText) {
// console.log(type)
container.style.display = 'block'
} else {
container.style.display = 'none'
}
})
let pokemonFilter = pokemon.filter((item) => {
// console.log(type);
if (item === item.type) {
// console.log(item);
return item;
}
})
// pokemon.filter((item) => {
// if (item === type) {
// return item;
// }
// })
// console.log(pokemon)
// console.log(pokemonFilter);
})
});
// console.log(pokemon);
}
// typeFilter();
fetchPokemon();
body {
// background-color: green;
margin: 0;
padding: 0;
}
// .logo {
// width: 50%
// }
// main {
// // background-image: url('imgs/pokeballcollection1.jpg');
// background-image: url('imgs/pokeballcollection2.jpg');
// }
.pokeContainer {
border: 2px solid black;
margin: 1rem;
background-color: rgb(255, 255, 255);
}
.flex-container {
display: flex;
// justify-content: space-between;
// justify-content: center;
text-align: center;
justify-content: space-around;
}
img {
// width: 100px;
width: 100%;
}
h3 {
text-align: center;
}
p {
width: 50px;
border: 1px solid black;
border-radius: 11px;
text-align: center;
background-color: rgb(95, 158, 160);
color: rgb(255, 255, 255);
}
ul {
padding: 0.5rem;
text-transform: uppercase;
}
ul.menu {
display: flex;
text-align: center;
}
li.list {
color: black;
}
li {
// border: 2px solid black;
width: 100px;
border-radius: 5px;
padding: 0.1rem;
list-style: none;
margin: 0.5rem;
// font-size: small;
font-size: 10px;
font-weight: 600;
// color: white;
}
.search {
display: flex;
justify-content: center;
}
.sort-method {
display: flex;
justify-content: center;
margin: 2rem 0;
button.sortAscending {
margin-right: 10px;
}
}
// .search {
// display: flex;
// justify-content: center;
// .search-bar {
// // background: url('../imgs/search-icon3.png') no-repeat 7px;
// background-size: 18px;
// // background-image: url('dist/css/pokemon-logo-png (1).png');
// }
// }
<!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">
<link rel="stylesheet" href="dist/css/styles.css">
<title>Pokemon API</title>
</head>
<body>
<main>
<header>
<nav>
<div class="navContainer">
<div class="logo">
<img src="imgs/pokemon-logo-png (1).png" alt="">
</div>
<div class="navLinks">
<ul class="menu">
<li class="list"><a>Home</a></li>
<li class="list"><a>Archive</a></li>
<li class="list"><a>Pokemon</a></li>
<li class="list"><a>About</a></li>
</ul>
</div>
</div>
</nav>
</header>
<div class="search">
<input type="text" class="search-bar" name="search" placeholder="search pokemon">
</div>
<div class="filterByType">
<button class="filter-btn">Grass</button>
<button class="filter-btn">Fire</button>
<button class="filter-btn">Water</button>
<button class="filter-btn">Electric</button>
<button class="filter-btn">Psyhcic</button>
<button class="filter-btn">Ground</button>
<button class="filter-btn">Steel</button>
<button class="filter-btn">Flying</button>
<button class="filter-btn">Bug</button>
<button class="filter-btn">Rock</button>
<button class="filter-btn">Fairy</button>
<button class="filter-btn">Dark</button>
</div>
<div class="sort-method">
<select name="drop-down" id="drop-down">
<option value="ID ASC">ID ASC</option>
<option value="ID DSC">ID DSC</option>
</select>
<!-- <button class="sortAscending">Sort A-Z</button>
<button class="sortDecending">Sort Z-A</button> -->
</div>
<div class="allPokemonContainer">
</div>
</main>
<script src="app4.js"></script>
</body>
</html>
So I created a 16 x 16 grid where I can etch a sketch on that grid. It's working well. Right now, I have to call the function createGrid(number) everytime I want to change the size of the grid. I have created a text input boxes as you can see on my code. So instead of having to write it again everytime and refresh the page, I want to be able to use the input from this box to change the size of the grid.
One of the ways that I've tried is by creating a new variable such as:
let number = inputFromBox.value;
and then write createGrid(number) . But it doesn't work. Is there any way how to make this work ? by using the input from the box ? Please help. Thank you !
let container = document.querySelector('.container');
let rows = document.getElementsByClassName('gridRow');
let duplicateOfInput = document.getElementById('duplicateOfInput');
let button = document.getElementById('submit');
let inputFromBox = document.getElementsByClassName('size-box');
button.addEventListener('click', createGrid);
createGrid(16);
draw();
// createGrid(anyNumber);
// draw();
// duplicateOfInput.textContent = `${input}`;
// const rainbow = document.getElementsByClassName('rainbow');
let reset = document.getElementById('clear-button');
reset.addEventListener('click', clearGrid);
function createGrid(number) {
makeRow(number);
makeColumn(number);
draw();
}
function makeRow(numberOfRow) {
container.innerHTML = "";
for (let i = 0; i <numberOfRow; i++) {
let row = document.createElement('div');
container.appendChild(row);
row.classList.add('gridRow');
}
}
function makeColumn(numberOfColumn) {
for ( let i = 0; i < rows.length; i++) {
for ( let j = 0; j < numberOfColumn; j++) {
let column = document.createElement('div');
rows[j].appendChild(column);
column.classList.add('gridColumn');
}
}
}
//adds event listener to all divs with class "column"
//added in global scope to allow drawing on page load
//this refers to the element triggering the mouseover event listener
function draw() {
let columns = document.getElementsByClassName("gridColumn");
for (let i = 0; i < columns.length; i++) {
columns[i].addEventListener("mouseover", changeColor);
}
function changeColor() {
let blue = document.getElementById('blue');
let eraser = document.getElementById('eraser');
let black = document.getElementById('black');
let rainbow = document.getElementById('rainbow');
if (blue.checked) {
this.style.backgroundColor = 'blue';
} else if (eraser.checked) {
this.style.backgroundColor = 'beige';
} else if (black.checked) {
this.style.backgroundColor = 'black';
} else if (rainbow.checked) {
let randomColor = Math.floor(Math.random()*16777215).toString(16);
this.style.backgroundColor = '#' + randomColor;
}
}
}
//eraser function loops through all column divs and sets background to "" in DOM
function clearGrid() {
let columns = document.getElementsByClassName("gridColumn");
for (let i = 0; i < columns.length; i++) {
columns[i].style.backgroundColor = '';
}
}
#import url('https://fonts.googleapis.com/css2?family=Asap:wght#400;600;700&display=swap');
body {
display: flex;
height: 100%;
width: 100%;
flex-direction: column;
background-color: beige;
font-family: Asap, sans-serif;
margin: 0;
padding: 0;
justify-content: center;
align-content: center;
align-items: center;
background-repeat: no-repeat;
}
.header {
display: flex;
flex: 1;
justify-content: center;
}
#header-title {
font-family: Asap, sans-serif;
font-size: 18px;
}
#setGridSize {
display: inline-flex;
justify-content: center;
align-items: center;
flex: 1;
gap: 12px;
}
#guide {
text-align: center;
margin: 1px;
font-family: Asap, sans-serif;
color: red;
font-size: 13px;;
}
.canvas {
display: flex;
justify-content: center;
align-items: center;
}
.container {
display: flex;
flex-direction: column;
border: 1px solid green;
width: 550px;
height: 550px;
}
/* .gridColumn {
display: inline-flex;
border: 1px solid beige;
margin: -1px 0;
width: 30px;
height: 30px;
} */
.gridColumn {
flex: 1;
border: 1px solid beige;
}
.gridRow {
display: flex;
flex: 1;
}
.default {
background: beige;
}
#button-container {
margin: 3px;
}
#clear-button {
margin: 2px;
}
<!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>DOM Manipulation and Events</title>
<script src="javascript.js" defer></script>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1 class="header"> Let's sketch ! </h1>
<div id="setGridSize">
<p id="header-title"> Grid Size :</p>
<input type="text" placeholder="Size of Board" class="size-box">
<span id = "duplicateOfInput"></span>
<button id="submit" > Submit </button>
</div>
<p id="guide"> Enter a number between 2 to 99 </p>
<div class="canvas">
<div class="container"></div>
</div>
<div class="buttons">
<form id="button-container">
<input type="radio" id="blue" name="pen" value="blue-pen"><label for = "blue-pen"> Blue </label>
<input type="radio" id="eraser" name="pen" value="eraser"><label for = "eraser" > Eraser </label>
<input type="radio" id="black" name="pen" value="black-pen"> <label for = "black" > Black </label>
<input type="radio"id="rainbow" name="pen" value="black-pen"> <label for = "rainbow" > Rainbow </label>
</form>
</div>
<button id = "clear-button" > Clear </button>
</body>
</html>
You can use let inputFromBox = document.getElementById('size-box'); and with let number = inputFromBox.value; you can get the value within the click function.
CodePen
You're using document.getElementsByClassName, which is most likely returning an array. Try using inputFromBox[0].value or switching to finding it by an ID.
You may find it easier to use CSS Grid. It allows you to minimise the amount of code you write because you don't have to create rows and columns separately.
Additionally if you set up some CSS variables you can hook the value from the input directly into the stylesheet to update the dimensions of the grid.
// Cache the elements
const grid = document.querySelector('.grid');
const submit = document.querySelector('.submit');
const input = document.querySelector('.size');
// When the button is clicked call `createGrid`
submit.addEventListener('click', createGrid);
function createGrid() {
// Get the value from the input
const { value } = input;
// Array to hold the box strings
const boxes = [];
// Loop to create a grid of boxes - for each
// box push it into the array
for (let i = 1; i <= value * value; i++) {
boxes.push(`<div class="box">${i}</div>`);
}
// `join` the array and update the innerHTML
// of the grid element
grid.innerHTML = boxes.join('');
// Pass the value directly into the spreadsheet.
// This changes the default `--grid-dimension` to the new value
document.documentElement.style.setProperty('--grid-dimension', value);
}
:root { --box-width: 30px; --grid-dimension: 13; }
.grid { margin-top: 1em; display: grid; grid-template-columns: repeat(var(--grid-dimension), var(--box-width)); gap: 0.2em; }
.box { display: flex; justify-content: center; align-items: center; height: var(--box-width); width: var(--box-width); background-color: lightgreen; }
.box:hover { background-color: lightblue; cursor: pointer; }
<input type="text" placeholder="Size of grid" class="size">
<button type="button" class="submit">Create grid</button>
<div class="grid"></div>
I created a 16 x 16 grid where I can etch a sketch on that grid. It's working with the default colour that I use. When I try adding buttons to change colours to sketch. I can't seem to make it work. I've tried various methods and writing it with various ways but again and again I failed. I want when I click on the buttons, it changes colour when I sketch. I'll include below the previous code that's working and one of the ways that I've tried. Any expert/master please have a look on my code.
let container = document.querySelector('.container');
let rows = document.getElementsByClassName('gridRow');
let columns = document.getElementsByClassName('gridColumn');
const blue = document.getElementsByClassName('blue');
const eraser = document.getElementsByClassName('eraser');
const black = document.getElementsByClassName('black');
let reset = document.getElementById('reset');
function createGrid(number) {
makeRow(number);
makeColumn(number);
changeColours();
}
function makeRow(numberOfRow) {
for (let i = 0; i <numberOfRow; i++) {
let row = document.createElement('div');
container.appendChild(row);
row.classList.add('gridRow');
}
}
function makeColumn(numberOfColumn, selection) {
for ( let i = 0; i < rows.length; i++) {
for ( let j = 0; j < numberOfColumn; j++) {
let column = document.createElement('div');
The part below is what I tried, erase it if you want it to work with just one colour
if (selection == 'blue') {
column.addEventListener('mouseenter', function() {
column.classList.add('blue');
})
} else if (selection == 'eraser') {
column.addEventListener('mouseenter', function() {
column.classList.add('eraser');
})
} else if (selection == 'black') {
column.addEventListener('mouseenter', function() {
column.classList.add('black');
})
} else {
column.addEventListener('mouseenter', function() {
column.classList.add('colored');
})
}
// column.addEventListener('mouseleave', () => {
// column.classList.remove('colored');
// })
Just erase part of the code above if you want to make it work
rows[j].appendChild(column);
column.classList.add('gridColumn');
}
}
}
The part below is what I tried, erase it if you want it to work with just one colour
blue.addEventListener('click', function() {
makeColumn(number, 'blue');
})
eraser.addEventListener('click', function() {
makeColumn(number, 'white');
})
black.addEventListener('click', function() {
makeColumn(number, 'black');
})
Just erase part of the code above if you want to make it work
createGrid(16);
#importurl('https://fonts.googleapis.com/css2family=Asap:wght#400;600;700&display=swap');
body {
display: flex;
height: 100%;
width: 100%;
flex-direction: column;
background-color: beige;
font-family: Asap, sans-serif;
margin: 0;
padding: 0;
justify-content: center;
align-content: center;
align-items: center;
}
.header {
display: flex;
flex: 1;
justify-content: center;
}
#setGridSize {
display: inline-flex;
justify-content: center;
flex: 1;
gap: 12px;
}
#guide {
text-align: center;
margin: 1px;
font-family: Asap, sans-serif;
color: red;
font-size: 13px;;
}
.container {
display: flex;
justify-content: center;
align-content: center;
align-items: center;
border: 1px solid black;
width: 550px;
height: 550px;
}
.gridColumn {
display: inline-flex;
border: 1px solid beige;
margin: -1px 0;
width: 30px;
height: 30px;
}
.colored{
background: red;
}
.buttons {
display: flex;
flex: 1;
gap: 20px;
margin: 10px;
}
.blue {
background: blue;
}
.eraser {
background: white;
}
.black {
background: black;
}
<!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>DOM Manipulation and Events</title>
<script src="javascript.js" defer></script>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1 class="header"> Let's sketch ! </h1>
<div id="setGridSize">
<p> Grid size </p> <input type="text" placeholder="Size of Board" class="size-box">
<button id="submit" > Submit </button>
</div>
<p id="guide"> Enter a number between 2 to 99</p>
<div class="container"></div>
<div class="buttons">
<button class="blue"> Blue </button>
<button class="eraser" > Eraser </button>
<button class="black"> Black </button>
<button class="rainbow" > Rainbow </button>
<button class="reset" > Reset</button>
</div>
</body>
</html>
Maybe this small example will help you
const grid = document.querySelector('.grid');
const colorSelector = document.querySelector('input[type="color"]')
const COUNT = 8
for (let i = 0; i < COUNT; i++) {
for (let j = 0; j < COUNT; j++) {
const btn = document.createElement('button')
grid.appendChild(btn)
}
}
const btns = Array.from(grid.children)
btns.forEach(btn => {
btn.addEventListener('mouseenter', event => {
btn.style.backgroundColor = colorSelector.value;
})
})
#import "https://cdn.jsdelivr.net/gh/KunalTanwar/normalize/css/normalize.inter.min.css";
body {
height: 100%;
display: grid;
place-items: center;
}
.grid {
--btn-count: 8;
--btn-size: 24px;
display: grid;
grid-template-columns: repeat(var(--btn-count), var(--btn-size));
grid-template-rows: repeat(var(--btn-count), var(--btn-size));
}
.grid button {
border: 1px solid #d1d1d1;
}
<input type="color">
<div class="grid"></div>
Hi I'm making a search filter from the PokeAPI, but I'm getting a TypeError: Cannot read property 'filter' of undefined at HTMLInputElement. I want that when searching for a pokemon that it shows up. I probably do something wrong it could be a great help if some could help me with it. Thank you for your help.
const PokemonContainer = document.getElementById('pokemon__containerID');
const SearchContainer = document.getElementById('search__containerID');
const SearchElement = document.createElement('input');
SearchElement.setAttribute('type', 'text');
SearchElement.setAttribute('name', 'searchBar');
SearchElement.setAttribute('placeholder', 'Search...');
SearchContainer.appendChild(SearchElement);
const PokemonNumber = 151;
const createPokemonCard = (pokemon) => {
const PokemonElement = document.createElement('div');
const PokemonName = pokemon.name[0].toUpperCase() + pokemon.name.slice(1);
const PokemonID = pokemon.id;
const PokemonType = pokemon.types[0].type.name;
const PokemonTypeColors = {
fire: '#EE8130',
grass: '#7AC74C',
eletric: '#F7D02C',
water: '#6390F0',
ground: '#E2BF65',
rock: '#B6A136',
fairy: '#D685AD',
poison: '#A33EA1',
bug: '#A6B91A',
dragon: '#6F35FC',
psychic: '#F95587',
flying: '#A98FF3',
fighting: '#C22E28',
normal: '#A8A77A',
ice: '#96D9D6',
ghost: '#735797',
dark: '#705746',
steel: '#B7B7CE',
};
const AddColors = PokemonTypeColors[PokemonType];
PokemonElement.style.backgroundColor = AddColors;
const PokemonInnerHTML = `
<div class="pokemon__imageContainer">
<img src="https://pokeres.bastionbot.org/images/pokemon/${PokemonID}.png" />
</div>
<div class="pokemon__infomationContainer">
<span class="pokemon__id">#${PokemonID.toString().padStart(3, '0')}</span>
<h3 class="pokemon__name">${PokemonName}</h3>
<small class="pokemon__type">Type: <span>${PokemonType}</span></small>
</div>`;
PokemonElement.setAttribute('class', 'pokemon__card');
PokemonElement.innerHTML = PokemonInnerHTML;
PokemonContainer.appendChild(PokemonElement);
};
const getPokemons = async (id) => {
const api_url = `https://pokeapi.co/api/v2/pokemon/${id}`;
const response = await fetch(api_url);
const data = await response.json();
createPokemonCard(data);
createSearchFilter(data);
};
const receivePokemons = async () => {
for (let item = 1; item <= PokemonNumber; item++) {
await getPokemons(item);
}
};
receivePokemons();
const createSearchFilter = (pokemonData) => {
console.log(pokemonData);
SearchElement.addEventListener('keyup', (event) => {
const SearchValue = event.target.value;
const FilteredPokemons = pokemonData.filter((pokemon) => {
return (
pokemon.name.includes(SearchValue) || pokemon.id.includes(SearchValue)
);
});
createPokemonCard(FilteredPokemons);
console.log(FilteredPokemons);
});
};
createSearchFilter();
#import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght#0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #efefbb;
background: -webkit-linear-gradient(to right, #d4d3dd, #efefbb);
background: linear-gradient(to right, #d4d3dd, #efefbb);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-family: 'Lato';
}
h1 {
letter-spacing: 3px;
}
.pokemon__container {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: space-between;
max-width: 100vw;
}
.pokemon__card {
background: #eeeeee;
border-radius: 20px;
padding: 20px 40px;
margin: 10px;
box-shadow: 0 3px 15px rgba(100, 100, 100, 0.6);
}
.pokemon__imageContainer {
margin-top: 20px;
width: 120px;
height: 120px;
}
.pokemon__imageContainer img {
width: 100%;
}
.pokemon__infomationContainer {
margin-top: 20px;
text-align: center;
}
.pokemon__id {
background: #ffffff80;
border-radius: 10px;
font-size: 1rem;
padding: 5px 10px;
}
.pokemon__name {
margin: 15px 0 7px 0;
letter-spacing: 1px;
}
<!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>
<script src="function.js" defer></script>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<h1>PokeDex</h1>
<div class="search__container" id="search__containerID"></div>
<div class="pokemon__container" id="pokemon__containerID"></div>
</body>
</html>
The problem is you're calling createSearchFilter again and again inside getPokemons which is the root of the problem.
What I would suggest is after you get all the date call createSearchFilter once and no need to pass in any data, we will hide/show the DOM elements.
One additional thing that I would suggest is add an id to the pokemon__card and set it equal to the pokemon's name, this will make searching fairly simple.
PokemonElement.setAttribute("id", PokemonName);
Next, inside createSearchFilter function grab all pokemon cards from the DOM and listen for the keyup event. Inside the event listener check if the card's id includes the search term.
If it does, set the display of the card to block.
If it doesn't, set it to none.
const PokemonContainer = document.getElementById("pokemon__containerID");
const SearchContainer = document.getElementById("search__containerID");
const SearchElement = document.createElement("input");
SearchElement.setAttribute("type", "text");
SearchElement.setAttribute("name", "searchBar");
SearchElement.setAttribute("placeholder", "Search...");
SearchContainer.appendChild(SearchElement);
const PokemonNumber = 10;
const createPokemonCard = (pokemon) => {
const PokemonElement = document.createElement("div");
const PokemonName = pokemon.name[0].toUpperCase() + pokemon.name.slice(1);
PokemonElement.setAttribute("id", PokemonName);
const PokemonID = pokemon.id;
const PokemonType = pokemon.types[0].type.name;
const PokemonTypeColors = {
fire: "#EE8130",
grass: "#7AC74C",
eletric: "#F7D02C",
water: "#6390F0",
ground: "#E2BF65",
rock: "#B6A136",
fairy: "#D685AD",
poison: "#A33EA1",
bug: "#A6B91A",
dragon: "#6F35FC",
psychic: "#F95587",
flying: "#A98FF3",
fighting: "#C22E28",
normal: "#A8A77A",
ice: "#96D9D6",
ghost: "#735797",
dark: "#705746",
steel: "#B7B7CE",
};
const AddColors = PokemonTypeColors[PokemonType];
PokemonElement.style.backgroundColor = AddColors;
const PokemonInnerHTML = `
<div class="pokemon__imageContainer" id="${PokemonName}">
<img src="https://pokeres.bastionbot.org/images/pokemon/${PokemonID}.png" />
</div>
<div class="pokemon__infomationContainer">
<span class="pokemon__id">#${PokemonID.toString().padStart(3, "0")}</span>
<h3 class="pokemon__name">${PokemonName}</h3>
<small class="pokemon__type">Type: <span>${PokemonType}</span></small>
</div>`;
PokemonElement.setAttribute("class", "pokemon__card");
PokemonElement.innerHTML = PokemonInnerHTML;
PokemonContainer.appendChild(PokemonElement);
};
const getPokemons = async (id) => {
const api_url = `https://pokeapi.co/api/v2/pokemon/${id}`;
const response = await fetch(api_url);
const data = await response.json();
createPokemonCard(data);
};
const receivePokemons = async () => {
for (let item = 1; item <= PokemonNumber; item++) {
await getPokemons(item);
}
createSearchFilter();
};
receivePokemons();
const createSearchFilter = (pokemonData) => {
const cards = document.querySelectorAll(".pokemon__card");
SearchElement.addEventListener("keyup", (event) => {
const val = event.target.value.toLowerCase();
cards.forEach((card) => {
if (card.id.toLowerCase().includes(val)) {
card.style.display = "block";
} else {
card.style.display = "none";
}
});
});
};
#import url('https://fonts.googleapis.com/css2?family=Lato:ital,wght#0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #efefbb;
background: -webkit-linear-gradient(to right, #d4d3dd, #efefbb);
background: linear-gradient(to right, #d4d3dd, #efefbb);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-family: 'Lato';
}
h1 {
letter-spacing: 3px;
}
.pokemon__container {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: space-between;
max-width: 100vw;
}
.pokemon__card {
background: #eeeeee;
border-radius: 20px;
padding: 20px 40px;
margin: 10px;
box-shadow: 0 3px 15px rgba(100, 100, 100, 0.6);
}
.pokemon__imageContainer {
margin-top: 20px;
width: 120px;
height: 120px;
}
.pokemon__imageContainer img {
width: 100%;
}
.pokemon__infomationContainer {
margin-top: 20px;
text-align: center;
}
.pokemon__id {
background: #ffffff80;
border-radius: 10px;
font-size: 1rem;
padding: 5px 10px;
}
.pokemon__name {
margin: 15px 0 7px 0;
letter-spacing: 1px;
}
<!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>
<script src="function.js" defer></script>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<h1>PokeDex</h1>
<div class="search__container" id="search__containerID"></div>
<div class="pokemon__container" id="pokemon__containerID"></div>
</body>
</html>
createSearchFilter() have to take parameter but in your code don't take any param that's why pokemonData is undefined
I need to add a click event to a css class so when clicked it switches to a different class. Specifically, I have a character class on li items that I would like to change to another class when the li item is clicked. Code:
html
<!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>Document</title>
<link rel="stylesheet" href="app.css" />
</head>
<body>
<div class="container">
<h1>Client Search</h1>
<div id="searchWrapper">
<input
type="text"
name="searchBar"
id="searchBar"
placeholder="search for a character"
onkeyup="myFunction()"
/>
</div>
<ul id="charactersList"></ul>
</div>
<script src="app.js"></script>
</body>
</html>
css
body {
font-family: sans-serif;
background-color: #111d4a;
}
* {
box-sizing: border-box;
}
h1 {
color: #eee;
margin-bottom: 30px;
}
.container {
padding: 40px;
margin: 0 auto;
max-width: 1000px;
text-align: center;
}
#charactersList {
padding-inline-start: 0;
display: none;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
grid-gap: 20px;
}
.character {
list-style-type: none;
background-color: #eaeaea;
border-radius: 3px;
padding: 10px 20px;
display: grid;
grid-template-columns: 3fr 1fr;
grid-template-areas:
'name image'
'house image';
text-align: left;
}
.character:hover {
background-color: blue;
cursor: pointer;
}
.character > h2 {
grid-area: name;
margin-bottom: 0px;
}
.character > p {
grid-area: house;
margin: 0;
}
#searchBar {
width: 100%;
height: 32px;
border-radius: 3px;
border: 1px solid #eaeaea;
padding: 5px 10px;
font-size: 12px;
}
#searchWrapper {
position: relative;
}
#searchWrapper::after {
content: '🔍';
position: absolute;
top: 7px;
right: 15px;
}
javaScript
const charactersList = document.getElementById('charactersList');
const searchBar = document.getElementById('searchBar');
let clientNames = [];
searchBar.addEventListener('keyup', (e) => {
const searchString = e.target.value.toLowerCase();
const filteredCharacters = clientNames.filter((character) => {
return (
character.name.toLowerCase().includes(searchString) ||
character.house.toLowerCase().includes(searchString)
);
});
displayCharacters(filteredCharacters);
});
const loadCharacters = async () => {
try {
const res = await fetch('https://hp-api.herokuapp.com/api/characters');
clientNames = await res.json();
displayCharacters(hpCharacters);
} catch (err) {
console.error(err);
}
};
const displayCharacters = (characters) => {
const htmlString = characters
.map((character) => {
return `
<li class="character">
<h2>${character.name}</h2>
<p>House: ${character.house}</p>
</li>
`;
})
.join('');
charactersList.innerHTML = htmlString;
};
loadCharacters();
//change the display of characterListfrom none to grid
function myFunction() {
var charactersList = document.getElementById("charactersList");
charactersList.style.display = "grid";
//also check if searchBar is empty and set display back to none
var searchBar = document.getElementById("searchBar").value;
if (searchBar === ""){
charactersList.style.display = "none";
}
}
Great question!
I just made a CodePen to illustrate how to programmatically change CSS class names when a li item is clicked. Check out this example and let me know if this clarifies the problem : )
JS
let list = document.getElementById('myList');
let items = ['First', 'Second', 'Third', 'Fourth', 'Fifth'];
for(let item of items){
let li = document.createElement("LI");
li.appendChild(document.createTextNode(item));
li.classList.add('blue');
li.addEventListener("click", () => {
li.classList.remove('blue');
li.classList.add('red');
});
list.appendChild(li);
}
HTML
<ul id="myList"></ul>
CSS
.blue{
color: blue;
}
.red{
color: red;
}
https://codepen.io/CrowlsYung/pen/eYJRPjx
Suggested Change
<li class="character" onclick="handleItemClick(event)">
<h2>${character.name}</h2>
<p>House: ${character.house}</p>
</li>
function handleItemClick(e){
e.currentTarget.classList.toggle('prevClass')
e.currentTarget.classList.toggle('newClass');
}