how to view items from api and add item to cart - javascript

im fetching items image , name ,price ,about from API
i fetched each item and added it in html tag the problem when i press add to cart button nothing adding
i tried onclick function on the button and call item by id
html page
<div id="api-1" class="images full">
</div>
js file
window.onload = function(){
const name = document.getElementById('api-1');
const tableItems = document.getElementById('item');
const cartContent = document.getElementsByClassName('table-cart');
fetch('https://us-central1-guitar-chord-de94e.cloudfunctions.net/products')
.then(response => response.json())
.then(items => {
let html = '';
items.forEach(item =>{
// console.log(item.items.name)
html += `
<div class="container">
<img src=${item.items.image} class="item">
<div class="overlay">
<p style="color:white">${item.items.name}</p>
<p style="color: white;font-weight: bold;font-size: 17px">price: ${item.items.price}</p>
<div style="margin-top:60px;">
<button onclick="addToCart()" style="background-color: gold;margin:0%;">add <img width="16px" src="./image/icons/shopping-cart.png" alt=""></button>
</div>
</div>
</div>
`;
name.innerHTML= html;
})
});
}
function addToCart(){
fetch('https://us-central1-guitar-chord-de94e.cloudfunctions.net/products')
.then(response => response.json())
.then(sys => {
sys.forEach(item =>{ console.log(item.sys);
});
});
}

You have to pass the id, button click handler like in below code.
<button onclick="addToCart(${item.sys.id})" style="background-color: gold;margin:0%;"></button>
Here's a working pen. https://codepen.io/anon/pen/jjojVm
I am capturing id of the clicked item in addToCart function. Using that id, you can maintain a cart in the same page or you can goto to different page passing the same id in URL depending on your requirement.

Related

How do I make images from this waifu API appear on page?

I've been stuck on this Waifu API for a bit now and want to ask for help.
I can get the JSON tags in the console and from there I'm able to navigate, click on the image, and see it. But I'm having trouble formatting it on the page with each click.
I know it's a stupid question, I just wanna make my friends at work laugh but also LEARN WHY IT ISN'T WORKING. :/
thank you for your time
<!-- ---waifuthingy----- -->
<div id="waifuContainer" class="container mt-5 text-center">
<h1 class="display-5 text-warning" id="dadJokeFont">Click for waifu:</h1>
<button id="waifuButton" class="btn btn-warning mt-5">uWu</button>
<div id="waifuImage" >
<img id="waifus" src="" alt=""> </div>
</div>
<!-- ----letmebe---- -->
// Waifu Image API
const waifuImage = document.querySelector('#waifuImage');
const waifuButton = document.querySelector('#waifuButton');
const makeImages = (waifus) => {
for(let result of waifus) {
const img = document.createElement('IMG');
img.src.url = result.show.image.medium;
document.body.append(img);
}
}
waifuButton.addEventListener('click', () => {
fetch('https://api.waifu.im/random')
.then(res => res.json())
.then(res => {
console.log(res.images)
waifuImage.src = res.url;
waifus = waifuImage;
})
.catch(err=>console.log(err))
})
Issues:
You are trying to set the src on the div rather than img
You are trying to set res.url, But the res doesn't have a URL. URL is in res.images[0].url.
const waifuImage = document.querySelector('#waifus');
const waifuButton = document.querySelector('#waifuButton');
const makeImages = (waifus) => {
for (let result of waifus) {
const img = document.createElement('IMG');
img.src.url = result.show.image.medium;
document.body.append(img);
}
}
waifuButton.addEventListener('click', () => {
fetch('https://api.waifu.im/random')
.then(res => res.json())
.then(res => {
waifuImage.src = res.images[0].url;
})
.catch(err => console.log(err))
})
#waifus {
width: 100%;
object-fit: contain;
}
<div id="waifuContainer" class="container mt-5 text-center">
<h1 class="display-5 text-warning" id="dadJokeFont">Click for waifu:</h1>
<button id="waifuButton" class="btn btn-warning mt-5">uWu</button>
<div id="waifuImage">
<img id="waifus" src="" alt="">
</div>
</div>

How to get the value of an element only if another specific element is visible?

What I am working with:
<ul class="abc">
<li class="xyz">
<a href="www.something.com">
<div>
<h2>
<div>
<div class="theText">
<div>Get this text</DIV>
</div>
</div>
</h2>
</div>
</a>
<button aria-label="remove">...</button>
</li>
<li class="xyz">...Same stuff here as above li...</li>
<li class="xyz">...Same stuff here as above li...</li>
<li class="xyz">...Same stuff here as above li...</li>
</ul>
The button here has two states for the aria-label attribute which is remove (for when the button is clicked) and add (for when the button is not yet clicked).
What I want to achieve:
I want to get the value within the <a> tag, which in this case is "Get this text", BUT only if the button within its same <li> tag is set to aria-label="remove". I will also be storing the values that I get within an array to later on compare with another array.
What I have tried:
let myArray: any = []
cy.get('li[class="xyz"]').each(($element) => {
cy.get('li[class="xyz"]').within(($element) => {
cy.wrap($element)
.find('button[aria-label="remove"]')
.find('div[class="theText"]')
.invoke('text').then(text => {
myArray.push(text)
})
})
}).then(() => {
cy.wrap(myArray).as('myArray')
})
With the above code, I am getting this Assertion Error from Cypress.
If you want to use the :has() pseudo-selector, you should do so on the outer of the .each() loop.
But please beware, :has() pseudo-selector will fail if there are zero buttons already clicked.
let myArray: any = []
cy.get('li[class="xyz"]:has(button[aria-label="remove"])') // implied filter
.each($li => {
// only element with remove attribute inside here
cy.wrap($li)
.find('div[class="theText"]')
.invoke('text')
.then(text => {
myArray.push(text)
})
})
}).then(() => {
cy.wrap(myArray).as('myArray')
})
This is the "old" way to do conditional checking, but the .if() command is better because it has built-in retry when loading asynchronous data.
let myArray: any = []
cy.get('li[class="xyz"]').each(($element) => {
// Use jquery to check the button has remove attribute
const removeButton = $element.find('button[aria-label="remove"]')
if (removeButton.length) {
cy.wrap($element).find('div[class="theText"]')
.invoke('text').then(text => {
myArray.push(text)
})
}
}).then(() => {
cy.wrap(myArray).as('myArray')
})
Use the cypress-if package
let myArray: any = []
cy.get('li[class="xyz"]').each(($element) => {
cy.wrap($element).within(() => {
cy.get('button[aria-label="remove"]')
.if() // any chained commands will only run
// if [aria-label="remove"] exists
// but the test does not fail
// if [aria-label="remove"] does not exist
.parent() // move up to parent to avoid your error msg
.find('div[class="theText"] div')
.invoke('text').then(text => {
myArray.push(text)
})
})
}).then(() => {
cy.wrap(myArray).as('myArray')
})
cy.get('#myArray')
.should('deep.eq', ['Get this text']) // passes
Sample HTML for testing
<ul class="abc">
<li class="xyz">
<a href="www.something.com">
<div>
<h2>
<div>
<div class="theText">
<div>Get this text</DIV>
</div>
</div>
</h2>
</div>
</a>
<button aria-label="remove">...</button>
</li>
<li class="xyz">
<a href="www.somethingelse.com">
<div>
<h2>
<div>
<div class="theText">
<div>Not this text</DIV>
</div>
</div>
</h2>
</div>
</a>
<button aria-label="add">...</button>
</li>
</ul>
Result: ['Get this text']
Note I added and extra div here .find('div[class="theText"] div') to avoid whitespace around the text, but it doesn't alter the conditional check.
let myArray = []
const buttonCheck = document.querySelector("button").getAttribute("aria-label");
if(buttonCheck === "remove"){
const aTagInnerText = document.querySelector("a").innerText;
myArray.push(aTagInnerText.trim(" "));
}
console.log(myArray)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<ul class="abc">
<li class="xyz">
<a href="www.something.com">
<div>
<h2>
<div>
<div class="theText">
<div>Get this text</DIV>
</div>
</div>
</h2>
</div>
</a>
<button aria-label="remove">...</button>
</li>
<li>...Same stuff here as above li...</li>
<li>...Same stuff here as above li...</li>
<li>...Same stuff here as above li...</li>
</ul>
</body>
</html>
You can use has in your selector
let myArray: any = []
cy.get('li[class="xyz"]:has(button[aria-label="remove"])').each(($element) => {
cy.get('li[class="xyz"]:has(button[aria-label="remove"])').within(($element) => {
cy.wrap($element)
.find('div[class="theText"]')
.invoke('text').then(text => {
myArray.push(text)
})
})
}).then(() => {
cy.wrap(myArray).as('myArray')
})
Or you can use parentsUntil to get back to the parent element after finding the related element with aria-label="remove"
let myArray: any = []
cy.get('li[class="xyz"]').each(($element) => {
cy.get('li[class="xyz"]').within(($element) => {
cy.wrap($element)
.find('button[aria-label="remove"]')
.parentsUntil('li[class="xyz"]')
.find('div[class="theText"]')
.invoke('text').then(text => {
myArray.push(text)
})
})
}).then(() => {
cy.wrap(myArray).as('myArray')
})

Trouble rendering items from api feed

I am trying to display the latest and top stories on a single homepage using the hacker news API feed. I am using the .map so the code will loop over each story and display it all in a div with an id of output.
From what I am able to see I need to call the first API feed that will give me the day's top 500 results. The first API will only return story IDs as integers. I then need to make a 2nd API call using each story id from the original API call and map over it to get the corresponding data to each story to display on my site.
The code is working and the results are being displayed however when I switch between the latest stories and the top stories I keep getting different results at the top. Should I be using async and await somewhere In my code?
function getNewPosts() {
document.getElementById('output').innerHTML = ``;
fetch('https://hacker-news.firebaseio.com/v0/newstories.json?print=pretty')
.then(response => response.json())
.then(storyIds => {
storyIds.map(function (id) {
return (
fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json?print=pretty`)
.then(response => response.json())
.then(story => {
// Display time human readable
let unixTimestamp = story.time;
let milliseconds = unixTimestamp * 1000;
let dateObject = new Date(milliseconds);
let humanDateFormat = dateObject.toLocaleString();
document.getElementById('output').innerHTML += `
<div class="card mb-3">
<h5 id="post-title" class="card-header data-title mb-1">${story.title}</h5>
<div class="card-body">
<p class="off-white-text mb-0">${story.type} by: ${story.by}</p>
<p class="off-white-text mb-0">posted: ${humanDateFormat}</p>
<p class="off-white-text mb-0">link to article:<a class="post-url" href="${story.url}" target="_blank"> Click here</a></p>
</div>
</div>
`
})
)
})
})
}
function getTopPosts() {
document.getElementById('output').innerHTML = ``;
fetch('https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty')
.then(response => response.json())
.then(storyIds => {
storyIds.map(function (id) {
return (
fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json?print=pretty`)
.then(response => response.json())
.then(story => {
// Display time human readable
let unixTimestamp = story.time;
let milliseconds = unixTimestamp * 1000;
let dateObject = new Date(milliseconds);
let humanDateFormat = dateObject.toLocaleString();
document.getElementById('output').innerHTML += `
<div class="card mb-3">
<h5 id="post-title" class="card-header data-title mb-1">${story.title}</h5>
<div class="card-body">
<p class="mb-0 off-white-text">${story.type} by: ${story.by}</p>
<p class="mb-0 off-white-text">Posted: ${humanDateFormat}</p>
<p class="mb-0 off-white-text">Link to article:<a class="post-url" href="${story.url}" target="_blank"> Click here</a></p>
</div>
</div>
`
})
)
})
})
}
The user is able to switch between the top and newest posts by clicking on a button for each on the homepage
<!-- Action buttons -->
<div class="row">
<div class="col-12 col-md-12 text-center">
<button id="getPosts" class="btn my-1" onclick="getNewPosts()">Read Latest News</button>
<button id="getPosts" class="btn my-1" onclick="getTopPosts()">Read Top News</button>
<button id="getPosts" class="btn my-1" onclick="clearNews()">Reset All News</button>
<hr class="text-white">
</div>
</div>
Thanks for any help in advance

Why event listener does'n work others time same as first?

I have problem with this javascript code that I cant solve at all
btnClaim.addEventListener("click", () => {
rewardCurrent.style.display = "none";
claimedRewards.push(currentReward);
rewardsList.innerHTML = ``;
claimedRewards.forEach(function (rew, i) {
const html = `
<div class="reward">
<div class="img-text-cont">
<img src="${rew.imgUrl}" alt="">
<div class="text-cont">
<p class="claimed-reward-title">${rew.title}</p>
<p class="claimed-reward-price">$${rew.price}</p>
</div>
</div>
<div class="claimed-rewards-action">
<button class="btn-sell2" id="${i}">Sell</button>
<button class="btn-ship">Ship</button>
</div>
</div>
`;
rewardsList.insertAdjacentHTML("afterbegin", html);
});
const btnsShip = document.querySelectorAll(".btn-ship");
const btnsSell = document.querySelectorAll(".btn-sell2");
btnsSell.forEach(function (sell) {
sell.addEventListener("click", () => {
balance += Number(claimedRewards[sell.id].price);
balanceSum.textContent = `$${balance}`;
claimedRewards.splice(Number(sell.id), 1);
rewardsList.innerHTML = ``;
claimedRewards.forEach(function (rew, i) {
const html = `
<div class="reward">
<div class="img-text-cont">
<img src="${rew.imgUrl}" alt="">
<div class="text-cont">
<p class="claimed-reward-title">${rew.title}</p>
<p class="claimed-reward-price">$${rew.price}</p>
</div>
</div>
<div class="claimed-rewards-action">
<button class="btn-sell2" id="${i}">Sell</button>
<button class="btn-ship">Ship</button>
</div>
</div>
`;
rewardsList.insertAdjacentHTML("afterbegin", html);
});
});
});
btnsShip.forEach(function (ship) {
ship.addEventListener("click", () => {
claimedRewardsClose.style.display = "none";
wheelCont.style.filter = "blur(10px)";
thanksCont.style.display = "flex";
});
});
});
I have claim.addEventListener() that push some products to claimedRewards array, than insertAdjacentHTML() method fill shopping chart with that products information and two buttons(sell and ship), I have problem with sell button, when I click sell button on one product found will transfer back to wallet and this product will disappear from the chart and It is all good, but when I want to sell second product sell button doesn't work, it work if I hit claim button again and add new product, but again I only can sell one product, but second not, again it is possible if I hit again claim button and add new product. Is there any solution for my problem?

How can i add an "onclick function" inside a `literal template` which is inside a Class?

this if my first question here, so sorry for any mistake or if the question is too silly.
*I have a Class with a method that displays a country-card on screen. I need to add an onclick function to save the name of the country so I can access to it from another page. i don't know if there is a way to make it work.
Any ideas?
class UI {
constructor() {
this.cardsContainer = document.querySelector("#cards-container");
}
showCountries(data) {
data.forEach(country => {
let div = `
<div class="card">
// this is the onclick function i need to access
<a onclick="countrySelected(${this.country.borders})">
<div class="card-image">
<img src=${country.flag} alt="">
</div>
<div class="card-info">
<h2 class="card-name"> ${country.name}</h2>
<p><strong>Population:</strong> ${country.population}</p>
<p><strong>Region:</strong> ${country.region}</p>
<p><strong>Capital:</strong> ${country.bogota}</p>
</div>
</a>
</div>
`;
this.cardsContainer.innerHTML += div;
})
}
//method
countrySelected(data) {
sessionStorage.setItem('country', data);
}
}
I assume that the country.name is unique.
class UI {
constructor() {
this.cardsContainer = document.querySelector("#cards-container");
}
showCountries(data) {
data.forEach(country => {
let div = `
<div class="card">
// this is the onclick function i need to access
<a id=${country.name}>
<div class="card-image">
<img src=${country.flag} alt="">
</div>
<div class="card-info">
<h2 class="card-name"> ${country.name}</h2>
<p><strong>Population:</strong> ${country.population}</p>
<p><strong>Region:</strong> ${country.region}</p>
<p><strong>Capital:</strong> ${country.bogota}</p>
</div>
</a>
</div>
`;
this.cardsContainer.innerHTML += div;
document.querySelector(`a[id="${country.name}"]`)
.addEventListener('click', () => countrySelected(country.borders));
})
}
//method
countrySelected(data) {
sessionStorage.setItem('country', data);
}
}
Also, you can refer to this post: Setting HTML Button`onclick` in template literal

Categories