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
Related
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>
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?
I've been trying to access the array results from my fetch api request. I can get the results to return and parse it from json into a javascript object. However I cant access the results. The array is that is return called results. I wondering what I'm missing. The ultimate aim of the project is to get 12 random profiles from the api and get it to display to the card div. The error message I'm getting is 'Uncaught (in promise) TypeError: Cannot read property 'results' of undefined at app.js:40'
HTML
<!DOCTYPE html>
<html lang="en-US">
<head>
<title>Public API Requests</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link href="css/normalize.css" rel="stylesheet">
<link href="css/styles.css" rel="stylesheet">
</head>
<body>
<header>
<div class="header-inner-container">
<div class="header-text-container">
<h1>AWESOME STARTUP EMPLOYEE DIRECTORY</h1>
</div>
<div class="search-container">
</div>
</div>
</header>
<div id="gallery" class="gallery">
</div>
</body>
<script type="text/javascript" src="app.js"></script>
</html>
Javascript
const gallery = document.getElementById('gallery');
const card = document.createElement('div');
card.classList.add('card');
gallery.appendChild(card);
function fetchData(url) {
return fetch(url)
.then(response => { return response.json()})
.then(data => {console.log(data)})
.catch(error => {console.log('Error with fetching API', error)})
}
function generateInfo(data) {
const info = data.map( item => `
<div class="card-img-container">
<img class="card-img" src="${data}" alt="profile picture">
</div>
<div class="card-info-container">
<h3 id="name" class="card-name cap">${name.first} ${name.last}</h3>
<p class="card-text">${data.email}</p>
<p class="card-text cap">${location.city}</p>
</div>
`)
card.innerHTML = info;
}
fetchData('https://randomuser.me/api/')
.then(data => generateInfo(data.results));
The error is clear, the object you are getting in data is not defined, that's why it does not have a result key.
Check that data is coming from the URL. When I fetch the URL there is JSON coming in.
Also note that in the second then you have for debugging is not returning the data variable, and that's why you get nothing afterwards.
Add a return statement like: return data;
Extra info related to the catch part from docs: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API if you want to check for errors look at the status code from response.
The Promise returned from fetch() won’t reject on HTTP error status even if the response is an HTTP 404 or 500. Instead, it will resolve normally (with ok status set to false), and it will only reject on network failure or if anything prevented the request from completing.
Change the fetchData function, remove .then block where you are getting final data, attach it when calling fetchData
function fetchData(url) {
return fetch(url)
.then(response => { return response.json()})
.catch(error => {console.log('Error with fetching API',
error)})}
fetchData('https://randomuser.me/api/')
.then(data =>generateInfo(data.results)); //success to the final promise
Now inside generate info use foreach() instead of map().Since for each user object you need to create card.
function generateInfo(results) {
results.forEach( userObj =>{
const card = document.createElement('div');
card.classList.add('card');
card.innerHTML = `
<div class="card-img-container">
<img class="card-img" src="${userObj.picture.thumbnail}" alt="profile picture">
</div>
<div class="card-info-container">
<h3 id="name" class="card-name cap">${userObj.name.first} ${name.last}</h3>
<p class="card-text">${userObj.email}</p>
<p class="card-text cap">${userObj.location.city}</p>
</div>
`;
gallery.appendChild(card);
})
}
Run the following snippet to check if it works.
const gallery = document.getElementById('gallery');
function fetchData(url) {
return fetch(url)
.then(response => { return response.json()})
.catch(error => {console.log('Error with fetching API', error)})}
function generateInfo(results) {
results.forEach( userObj =>{
const card = document.createElement('div');
card.classList.add('card');
card.innerHTML = `
<div class="card-img-container">
<img class="card-img" src="${userObj.picture.thumbnail}" alt="profile picture">
</div>
<div class="card-info-container">
<h3 id="name" class="card-name cap">${userObj.name.first} ${name.last}</h3>
<p class="card-text">${userObj.email}</p>
<p class="card-text cap">${userObj.location.city}</p>
</div>
`;
gallery.appendChild(card);
})
}
fetchData('https://randomuser.me/api/')
.then(data =>generateInfo(data.results));
<header>
<div class="header-inner-container">
<div class="header-text-container">
<h1>AWESOME STARTUP EMPLOYEE DIRECTORY</h1>
</div>
<div class="search-container">
</div>
</div>
</header>
<div id="gallery" class="gallery">
</div>
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.
I’m trying to create a „weather app” which is supposed to look like this: https://pictr.com/image/05IPpQ
I created an html markup, which looks like this:
<div class="card">
<div class="card__box card__box--blue" draggable="true" id="box1">
<div class="card__box--icon"></div>
<div class="card__box--city"></div>
<div class="card__box--country"></div>
<div class="card__box--weather"></div>
<div class="card__box--temperature"></div>
<div class="card__box--close">
<i class="fa fa-window-close" aria-hidden="true"></i>
</div>
</div>
<div class="card__box card__box--orange" draggable="true" id="box2">
<div class="card__box--icon"></div>
<div class="card__box--city"></div>
<div class="card__box--country"></div>
<div class="card__box--weather"></div>
<div class="card__box--temperature"></div>
<div class="card__box--close">
<i class="fa fa-window-close" aria-hidden="true"></i>
</div>
</div>
<div class="card__box card__box--grey" draggable="true" id="box3">
<div class="card__box--icon"></div>
<div class="card__box--city"></div>
<div class="card__box--country"></div>
<div class="card__box--weather"></div>
<div class="card__box--temperature"></div>
<div class="card__box--close">
<i class="fa fa-window-close" aria-hidden="true"></i>
</div>
</div>
<div class="card__box card__box--new" draggable="false" id="empty">
<div class="card__box--add">
<i class="fa fa-plus" aria-hidden="true"></i>
</div>
</div>
<p class="card__paragraph paragraph--smallest paragraph--grey text-center">Add more widgets</p>
</div>
I’m trying to make this actually work by the use of https://openweathermap.org.
This is an example of the APIs’ response which I’m getting:
https://samples.openweathermap.org/data/2.5/group?id=524901,703448,2643743&units=metric&appid=b6907d289e10d714a6e88b30761fae22
My problem is that I don’t know how to iterate through the response and fill all of my ‚boxes’ with proper data from the API. I want the first object from the list to fill the first box, etc. Here’s my code.
document.addEventListener('DOMContentLoaded', getWeather);
// These are hard coded ID's of the cities (only way to get data for multiple cities without a premium account)
const locations = ['524901', '703448', '2643743'];
const weather = new Weather();
function getWeather() {
const ui = new UI();
weather
.getWeather()
.then(response => ui.display(response.list))
.catch(err => console.log(err));
}
class Weather {
constructor(locations) {
this.apiKey = 'b5f8df2f8d10af0fda257b295738dcdd';
this.locations = locations;
}
// Fetch data from API
async getWeather() {
const response = await fetch(
`http://api.openweathermap.org/data/2.5/group?id=${locations}&units=metric&appid=${
this.apiKey
}`
);
const responseData = await response.json();
return responseData;
}
}
The display function is currently hardcoded to get the first object from the list, which is something i’m trying to avoid, and is currently left as is, just so that the app ‚works’.
class UI {
constructor() {
this.city = document.querySelector('.card__box--city');
this.country = document.querySelector('.card__box--country');
this.weather = document.querySelector('.card__box--weather');
this.temperature = document.querySelector('.card__box--temperature');
this.icon = document.querySelector('.card__box--icon');
}
display(response) {
this.city.textContent = response[0].name;
this.country.textContent = response[0].sys.country;
this.weather.textContent = response[0].weather[0].description;
this.temperature.textContent =
Math.ceil(response[0].main.temp) + String.fromCharCode(176);
const iconCode = response[0].weather[0].icon;
this.icon.style.backgroundImage = `url(http://openweathermap.org/img/w/${iconCode}.png)`;
}
}
I suspect there might be a problem with the UI constructor.