This is an update to a previous question I had. I am making a simple page that filters the first 9 Pokemon by their type after clicking a button. I will include the code below. I ran the code through a validator and there were no issues. Also, I don't see any errors in the console. I did console the type and the array every time a button is clicked so it looks like the filter is working. But, nothing is happening on the page.
Here's a link to the page: https://sobreratas.github.io/pokemonfilter/
const pokemon=[{name:"Bulbasaur",image:"images/bulbasaur.png",number:1,type:"Grass"},{name:"Ivysaur",image:"images/ivysaur.png",number:2,type:"Grass"},{name:"Venusaur",image:"images/venusaur.png",number:3,type:"Grass"},{name:"Charmander",image:"images/charmander.png",number:4,type:"Fire"},{name:"Charmeleon",image:"images/charmeleon.png",number:5,type:"Fire"},{name:"Charizard",image:"images/charizard.png",number:6,type:"Fire"},{name:"Squirtle",image:"images/squirtle.png",number:7,type:"Water"},{name:"Wartortle",image:"images/wartortle.png",number:8,type:"Water"},{name:"Blastoise",image:"images/blastoise.png",number:9,type:"Water"}];
const sectionCenter = document.querySelector('.section-center');
const btnContainer = document.querySelector('.btn_container');
window.addEventListener('DOMContentLoaded', function() {
displayPokemonMenu();
displayMenuButtons();
})
function displayPokemonMenu(array) {
let pokemonMap = pokemon.map(function(item) {
return `<div class="pokemon-item">
<img class="photo" src="${item.image}" alt="${item.name}">
<h2>${item.name}</h2>
<h3># <span id="number">${item.number}</span></h3>
<h4>Type: <span id="type">${item.type}</span></h4>
</div>`
})
pokemonMap = pokemonMap.join('');
sectionCenter.innerHTML = pokemonMap;
}
function displayMenuButtons() {
let types = pokemon.reduce(function(values, item) {
if (!values.includes(item.type)) {
values.push(item.type);
}
return values
}, ['All']);
const typesBtns = types.map(function(type) {
return `<button class="filter-btn" data-id="${type}">${type}</button>`
}).join('');
btnContainer.innerHTML = typesBtns;
const filterBtns = btnContainer.querySelectorAll('.filter-btn');
filterBtns.forEach(function(btn) {
btn.addEventListener('click', function(e) {
let type = e.currentTarget.dataset.id;
console.log(type)
const pokemonFilter = pokemon.filter(function(item) {
if (type === item.type) {
return item;
}
})
if (type === 'All') {
displayPokemonMenu(pokemon);
} else {
displayPokemonMenu(pokemonFilter);
console.log(pokemonFilter);
}
})
})
}
<img class="logo" src="images/logo.png" alt="logo">
<br>
<br>
<div class="btn_container">
<button class="filter-btn" data-id="All">All</button>
</div>
<div class="section-center">
<div class="pokemon-item">
<img class="photo" src="images/bulbasaur.png" alt="Bulbasaur">
<h2>Bulbasaur</h2>
<h3># <span id="number">1</span></h3>
<h4>Type: <span id="type">Grass</span></h4>
</div>
</div>
Related
I am a new learning JS. Who can help me complete this code. I have 2 problem:
render child Node user Chat when click without duplicate
how to remove child Node user when close chat window
full code is here: Jsfiddle
// event handling when click
handleEvents: function () {
let _this = this;
userChatList.onclick = function (e) {
const userNode = e.target.closest(".user-chat__item");
if (userNode) {
userIndex = Number(userNode.getAttribute("user-num"));
_this.renderUserChat(userIndex);
const getChatWithItems = document.querySelectorAll(".chat-with__item");
getChatWithItems.forEach(item => {
item.onclick = function(e){
const itemNode = e.target.closest(".chat-with__top i");
if(itemNode){
chatWithList.removeChild(chatWithItem);
}
}
})
}
}
},
//render user chat with someone
renderUserChat: function (num) {
// console.log(userIndex);
chatWithItem = document.createElement("li");
chatWithItem.classList.add("chat-with__item");
chatWithItem.setAttribute('user-num', num);
chatWithItem.innerHTML = `
<div class="chat-with__top">
<div class="chat-with__img">
<img src="${this.users[num].img}" alt="${this.users[num].name}">
<span class="user__status ${this.users[num].status}"></span>
</div>
<p class="chat-with__name">${this.users[num].name}</p>
<i class="fa-solid fa-xmark"></i>
</div>
<div class="chat-with__body">
<ul class="chat__text">
<li class="chat-text__user">Hey. 👋</li>
<li class="chat-text__user user__chatting">I am here</li>
<li class="chat-text__user user__chatting">What's going on?</li>
<li class="chat-text__user">Have you finished the "project 2" yet?</li>
<li class="chat-text__user user__chatting">I have been fixed bugs</li>
<li class="chat-text__user">OK.</li>
</ul>
</div>
<div class="chat-width__footer">
<i class="fa-solid fa-image"></i>
<i class="fa-solid fa-folder"></i>
<div class="chat-width__input">
<input type="text" id="send-sms" name="send SMS" placeholder="...">
</div>
<i class="fa-solid fa-paper-plane-top"></i>
</div>
`
chatWithList.appendChild(chatWithItem);
},
<ul class="chat-with__list">
</ul>
I have not still known how to solve it, up to now
Just keep track which chat windows are opened in an object.
To give you basic idea of the concept:
// storage for opened chat windows
// this variable must be accessible by event handlers
const openedChats = {};
In chat opened event handler:
if (openedChats[userId]) //check if chat already opened
return;
const chatWithItem = document.createElement("li");
...
openedChats[userId] = chatWithItem; //store window
chatWithList.appendChild(chatWithItem); //show window
In chat close event handler:
const chatWithItem = openedChats[userId]; // get opened chat
if (chatWithItem)
{
chatWithItem.parentNode.removeChild(chatWithItem); // destroy window
delete openedChats[userId]; // remove window
}
If you need to get list of all userIds that have opened chat windows, use:
const openedChatsIds = Object.keys(openedChats);
Finnaly I find the way to code. This is my way
handleEvents: function () {
let _this = this;
let currentChat = [];
userChatList.onclick = function (e) {
const userNode = e.target.closest(".user-chat__item");
if (userNode) {
userIndex = Number(userNode.getAttribute("user-num"));
// get value 'userIndex' for currentChat array
function getCurrentChat(arr, index) {
arr.push(index);
}
// check value userIndex in a currentChat array
function checkCurrentChat(arr, index) {
if (arr.indexOf(index) < 0) {
getCurrentChat(currentChat, userIndex);
return true;
} else {
return false;
}
}
let isExisted = checkCurrentChat(currentChat, userIndex);
// console.log(isExisted);
if (isExisted) {
_this.renderUserChat(userIndex);
}
const getChatWithItems = chatWithList.querySelectorAll(".chat-with__item");
getChatWithItems.forEach( function(item) {
item.onclick = function (e) {
const closeChat = e.target.closest(".chat-with__top i");
if(closeChat){
const getNum = Number(closeChat.parentElement.getAttribute("user-num"));
chatWithList.removeChild(item);
const findNum = currentChat.indexOf(getNum);
currentChat.splice(findNum, 1);
}
}
})
}
}
}
inside, i add an attribute to get number (userIndex):
<div class="chat-with__top" user-num ="${num}">
if you use second .parentElement, it will ok.
closeChat.parentElement.parentElement.getAttribute("user-num")
I was looking to shorten up this code if possible. I am making a TV show search app and the API I am using has some empty arrays in it. I was wondering if I can set some default parameters? I've been stuck on this for days! I know it's going to be an eye sore to read, but any help is much appreciated. Thank you for looking at my code.
const imgContainer = document.querySelector('.img-container')
const clearBtn = document.querySelector('.clear-btn')
searchForm.addEventListener('submit', function (e) {
e.preventDefault()
fetchApi()
})
const fetchApi = async () => {
const userInput = searchForm.elements.query.value
const config = { params: { q: userInput } }
const fetch = await axios.get('https://api.tvmaze.com/search/shows', config)
showDetails(fetch.data)
}
const showDetails = (request) => {
const reqMap = request.map(function (shows) {
const showImg = shows.show.image
const showTitle = shows.show.name
const showDesc = shows.show.summary
const showGenres = shows.show.genres[0]
if (showImg && showTitle && showDesc && showGenres) {
let showImgMed = shows.show.image.medium
return `<div class="show-details">
<h1>${showTitle}</h1>
<img class="stock-img" src="${showImgMed}" alt="">
<p class="show-desc">Description: ${showDesc}</p>
<p class="show-genre">Genre: ${showGenres}</p>
</div>`
} else if (!showGenres && !showImg && !showDesc) {
return `<div class="show-details">
<h1>${showTitle}</h1>
<img class="stock-img" src="https://www.westernheights.k12.ok.us/wp-content/uploads/2020/01/No-Photo-Available.jpg" alt="">
<p class="show-desc">Description: N/A</p>
<p class="show-genre">Genre: N/A</p>
</div>`
} else if (!showImg) {
return `<div class="show-details">
<h1>${showTitle}</h1>
<img class="stock-img" src="https://www.westernheights.k12.ok.us/wp-content/uploads/2020/01/No-Photo-Available.jpg" alt="">
<p class="show-desc">Description: ${showDesc}</p>
<p class="show-genre">Genre: ${showGenres}</p>
</div>`
} else if (!showDesc) {
let showImgMed = shows.show.image.medium
return `<div class="show-details">
<h1>${showTitle}</h1>
<img class="stock-img" src="${showImgMed}" alt="">
<p class="show-desc">Description: N/A</p>
<p class="show-genre">Genre: ${showGenres}</p>
</div>`
} else if (!showGenres) {
let showImgMed = shows.show.image.medium
return `<div class="show-details">
<h1>${showTitle}</h1>
<img class="stock-img" src="${showImgMed}" alt="">
<p class="show-desc">Description: ${showDesc}</p>
<p class="show-genre">Genre: N/A</p>
</div>`
}
}).join('')
imgContainer.innerHTML = reqMap
}
Define the varying values up front, then write out the HTML string once and interpolate. Change the mapper function to:
const {
image,
name,
summary = 'N/A',
genres,
} = shows.show;
const imageSrc = image ? image.medium : 'https://www.westernheights.k12.ok.us/wp-content/uploads/2020/01/No-Photo-Available.jpg';
const showGenres = genres[0] || 'N/A';
return `
<div class="show-details">
<h1>${name}</h1>
<img class="stock-img" src="${imageSrc}" alt="">
<p class="show-desc">Description: ${summary}</p>
<p class="show-genre">Genre: ${showGenres}</p>
</div>
`;
You can just normally render HTML and then change elements parameters via javascript.
var element = document.createElement('div');
element.innerHTML = `<div class="show-details">
<h1>aa</h1>
<img class="stock-img" src="aa" alt="">
<p class="show-desc">Description: aa</p>
<p class="show-genre">Genre: aa</p>
</div>`.trim();
Let's say your variable showGenres == false
if(!showGenres) {
element.querySelector("p.show-desc").textContent = "Genre: N/A"
}
You can have content defined once in element variable and then change it dynamically :)
https://developer.mozilla.org/en-US/docs/Web/API/Element/setAttribute
I'm trying my first weather api APP. Here I'm trying to achive that if the city weather is already displayed , It should give the message "You already know the weather" . and should not repeat the weather
Here is my code. Anyone Please look at my code ...
What is the mistake I have been made.
<div class="main">
<div class="container">
<div class="search_por">
<h2>Weather </h2>
<div class="validate_msg color_white"></div>
<form>
<label for=""></label>
<input type="search" class="input_text" value="">
<button type="submit" id="sub_button" class="srh_button">Search</button>
</form>
<!-- <canvas id="icon1" width="150" height="75"></canvas> -->
<div class="dat_weather">
<ul id="list_it">
</ul>
</div>
</div>
</div>
</div>
var get_text=document.querySelector("form");
get_text.addEventListener("submit",e=>{
e.preventDefault();
var input_val=document.querySelector('input').value;
const apiKey="bc4c7e7826d2178054ee88fe00737da0";
const url=`https://api.openweathermap.org/data/2.5/weather?q=${input_val}&appid=${apiKey}&units=metric`;
fetch(url,{method:'GET'})
.then(response=>response.json())
.then(data=>{console.log(data)
const{main,sys,weather,wind}=data;
//icons-end
var error_ms=document.getElementsByClassName("validate_msg")[0];
var iconcode = weather[0].icon;
console.log(iconcode);
var li=document.createElement("Li");
var weatherinfo=`<div class="nameci font_40" data-name="${data.name},${sys.country}"><span>${data.name}</span><sup>${sys.country}</sup></div>
<div class="temp_ic">
<img class="weat_icon" src="http://openweathermap.org/img/w/${iconcode}.png">
<div class="deg">${Math.floor( main.temp )}<sup>o</sup></div>
</div>
<div class="clear">
<div>${weather[0].description}</div>
</div>
`;
li.innerHTML=weatherinfo;
var ulid=document.getElementById("list_it");
ulid.appendChild(li);
var city_name=data.name;
console.log(skycons);
var listitems=document.querySelectorAll('#list_it');
const listArray=Array.from(listitems);
if(listArray.length>0)
{
var filtered_array=listArray.filter(el=>{
let content="";
if(input_val.includes(','))
{
if(input_val.split(',')[1].length>2)
{
alert("hving 2 commos");
inputval=input_val.split(',')[0];
content=el.querySelector(".nameci span").textContent.toLowerCase();
//content=el.querySelector(".nameci").innerHTML.toLowerCase();
//content=inputval.toLowerCase();
}
else
{
content=el.querySelector(".nameci").dataset.name.toLowerCase();
}
alert(filtered_array);
}
else
{
content=el.querySelector(".nameci span").textContent.toLowerCase();
}
console.log(inputval.toLowerCase());
return inputval.toLowerCase();
});
if(filtered_array.length>0)
{
console.log(filtered_array.length);
error_ms.innerHTML="You Already know the weather of this country....";
get_text.reset();
return;
}
}
})
.catch((error)=>{
error_ms.innerHTML="Please Enter a valid city Name";
});
var error_ms=document.getElementsByClassName("validate_msg")[0];
error_ms.innerHTML="";
//var get_text=document.querySelector("form");
get_text.reset();
});
My full code is here:
https://codepen.io/pavisaran/pen/wvJaqBg
Let's try keeping track of a list of displayed locations outside of the callback:
var get_text = document.querySelector("form");
// Keep Track Of Displayed Cities Here Instead
let displayed = [];
get_text.addEventListener("submit", e => {
e.preventDefault();
var input_val = document.querySelector('input').value;
const apiKey = "bc4c7e7826d2178054ee88fe00737da0";
const url = `https://api.openweathermap.org/data/2.5/weather?q=${input_val}&appid=${apiKey}&units=metric`;
fetch(url, {method: 'GET'})
.then(response => response.json())
.then(data => {
var error_ms = document.getElementsByClassName("validate_msg")[0];
const {main, sys, weather, wind, name} = data;
if (displayed.length > 0) {
// Filter Displayed Based on Current vs name from data (response)
const filtered_array = displayed.filter(el => el === name);
if (filtered_array.length > 0) {
error_ms.innerHTML = "You Already know the weather of this country....";
get_text.reset();
return Promise.resolve();
}
}
// Add City To Array of Displayed Cities
displayed.push(name);
// Do Rest of Code to Add New City
var iconcode = weather[0].icon;
var li = document.createElement("Li");
var weatherinfo = `<div class="nameci font_40" data-name="${data.name},${sys.country}"><span>${data.name}</span><sup>${sys.country}</sup></div>
<div class="temp_ic">
<img class="weat_icon" src="http://openweathermap.org/img/w/${iconcode}.png">
<div class="deg">${Math.floor(main.temp)}<sup>o</sup></div>
</div>
<div class="clear">
<div>${weather[0].description}</div>
</div>
`;
li.innerHTML = weatherinfo;
var ulid = document.getElementById("list_it");
ulid.appendChild(li);
})
.catch((error) => {
error_ms.innerHTML = "Please Enter a valid city Name";
});
var error_ms = document.getElementsByClassName("validate_msg")[0];
error_ms.innerHTML = "";
get_text.reset();
});
You have to just check for the value which is coming from api whether it's present on your list or not. you can try this.
li.innerHTML=weatherinfo;
var ulid=document.getElementById("list_it");
var isPresent = false;
var items = ulid.getElementsByTagName("li");
for (var i = 0; i < items.length; i++){
if(items[i].innerHTML == li.innerHTML){
alert("you already know the weather")
isPresent = true;
}
}
if(!isPresent){
ulid.appendChild(li);
}
I use the JavaScript code below to get and log the attribute value of a div.
I want to rewrite the JavaScript code using React. When I tried doing the same code in React. I get error: e.path.find is not a function
How The Function Works:
First,after clicking mealsEl, e.path.find is used to go through all the child elements of meals EL,
Then it returns the child elements containing the class Name: 'meal-info'
Then it checks if the child element containing class Name 'meal-info' also has an attribute of 'data-meal-id.
Then it logs the value of 'data-meal-id'
const mealsEL = document.getElementById('meals')
mealsEL.addEventListener('click', (e) => {
const mealInfo = e.path.find((item) => {
console.log(item)
if (item.classList) {
return item.classList.contains('meal-info');
} else {
return false;
}
});
console.log(mealInfo)
if (mealInfo) {
const mealID = mealInfo.getAttribute('data-mealid');
getMealByID(mealID);
}
});
<div class="container">
<div id="result-heading"></div>
<div id="meals" class="meals">
<div class="meal">
<img class="meal-img" src="https://source.unsplash.com/random" alt="" style="width:180px; height: 180px;border: solid #000 4px;"/>
<div class="meal-info" >
</div>
</div>
</div>
<div id="single-meal"></div>
</div>
<div id="result-heading"></div>
<div id="meals" class="meals">
<div class="meal">
<img class="meal-img" src="https://source.unsplash.com/random" alt="" style="width:180px; height: 180px;border: solid #000 4px;"/>
<div class="meal-info" >
</div>
</div>
const mealsEL = document.getElementById('meals')
mealsEL.addEventListener('click', (e) => {
const mealInfo = e.path.find((item) => {
if (item.classList) {
console.log(item.classList)
return item.classList.contains("meal-info");
} else {
return false;
}
});
// console.log(mealInfo)
if (mealInfo) {
const mealID = mealInfo.getAttribute('data-mealid');
// getMealByID(mealID);
console.log(mealID)
} else {
console.log('no')
}
});
<div id="meals" class="meals">
<div class="meal">
<img class="meal-img" src="" alt="">
<div class="meal-info" data-mealid="75757">
<h3>Click To Show Data Meal Id</h3>
</div>
</div>
<!-- When mealsEL is clicked, the function uses e.path.find to check if the mealsEl children element contain a className of 'meal-info' and stores the result in the variable `const meal-info`
// The second if statement checks if the child element containing className meal-info has an attribute of 'data-mealid'
// Then the value of data-mealid attribute from the child element is logged to the console
</div> -->
// React Code
const getMealByID = (e) => {
const NativePath = e.nativeEvent()
const mealInfo = NativePath.path.find((item) => {
console.log(mealInfo)
if (item.classList) {
return item.classList.contains('meal-info');
} else {
return false;
}
});
if (mealInfo) {
const mealID = mealInfo.getAttribute('data-mealid');
getMealByID(mealID);
}
}
<div id="meals" className="meals" onClick={getMealByID}>
{meals &&
meals.map((meal) => {
const src = meal.strMealThumb;
const mealID = meal.idMeal;
const alt = meal.strMeal;
const index = meal.idMeal;
// const mealIng = meal.strIngredient1;
const mealIng = [];
for (let i = 1; i <= 20; i++) {
if (meal[`strIngredient${i}`]) {
mealIng.push(
`${meal[`strIngredient${i}`]} - ${meal[`strMeasure${i}`]}`
);
} else {
break;
}
}
return (
<div className="meal" key={index}>
<img className="meal-img" src={src} alt="{alt}" />
<div className="meal-info" data-mealid={mealID}>
<h3>{alt}</h3>
</div>
<h2>{mealIng}</h2>
</div>
);
})}
You are getting the error because you are calling getMealByID with an invalid argument, the function expect an event as argument:
if (mealInfo) {
const mealID = mealInfo.getAttribute('data-mealid');
getMealByID(mealID); //--> mealID is not an event
}
Also I think you can get the mealInfo node using less code:
const getMealByID = e => {
const node = e.target;
const mealInfo = node.querySelector(".meal-info");
if (mealInfo) {
const mealID = mealInfo.getAttribute("data-mealid");
...
}
};
// In order to get the data-mealid attribute value from a div
// by using its parent's element . I had to use
// e.target.getAttribute("data-mealid") on a click event from the parents element.
function App() {
const getMealInfoAttribute = e => {
const mealIDData = e.target.getAttribute("data-mealid")
console.log(mealID)
};
return (
<div id="meals" className="meals" onClick={getMealInfoAttribute}>
<div className="meal" key={index}>
<img className="meal-img" src={src} alt="{alt}" />
<div className="meal-info" data-mealid={mealID}>
<h3>{alt}</h3>
</div>
</div>
);
</div>)
}
When I load my webpage up, the word "undefined" appears in a <ul> that is then modified with javascript and .innerHTML after the page is loaded up.
This is how the HTML appears:
<div>
<ul>
"undefined
"
<li>...</li>
</ul>
</div>
If there are no <li>'s, then it just appears as so:
<div>
<ul>undefined</ul>
</div>
Here is the Javascript function that seems to be causing it. The data parameter is the data from the database.
const setupBookmarks = (data) => {
let favoritesHTML, bookmarksHTML = '';
const bookmarkData = [];
if (data && data.length) {
data.forEach(doc => {
const bookmarkId = Math.floor(Math.random() * 10000000);
const bookmark = doc.data();
if (bookmark.favorite) {
favoritesHTML += bookmarkHTML(bookmark, bookmarkId);
} else {
bookmarksHTML += bookmarkHTML(bookmark, bookmarkId);
}
bookmarkData.push({bookmark, bookmarkId});
})
}
favoriteList.innerHTML = favoritesHTML;
bookmarkList.innerHTML = bookmarksHTML;
return bookmarkData;
}
Here is shortened version of the bookmarkHTML function, which simply adds the HTML to the favoritesHTML and bookmarksHTML variables in the previous function:
const bookmarkHTML = (bookmark, bookmarkId) => {
let html = '';
const li = `
<li>
<div class="row card-margin">
<div class="col s12 m12 card-padding">
<div class="card-panel teal card-size">
<img src='${"https://www.google.com/s2/favicons?domain_url=" + bookmark.url}' alt='icon' class='img-size'>
<a class='white-text' href='${bookmark.url}' target='_blank'>${bookmark.website}</a>
<button class='btn-flat btn-small right cross' id='${bookmarkId}'><i class='material-icons'>clear</i></button>
<button class='btn-flat waves-light btn-small right listener' id='${bookmarkId}'><i class='material-icons left'>compare_arrows</i>switch</button>
</div>
</div>
</div>
</li>
`;
html += li;
return html;
}
What could be causing this 'undefined' to appear in the HTML of my website upon being loaded up?