updating html from data retrieved in api call - javascript

I am new to web dev so please forgive.
I make simple api call
const getWorldTotal = async () => {
const response = await fetch('https://cors-anywhere.herokuapp.com/https://health-api.com/api/v1/covid-19/total');
const worldTotal = await response.json();
alert(worldTotal.total_confirmed)
document.getElementById('total') = worldTotal.total_confirmed
};
getWorldTotal()
Here is my html that i am trying to update
<div class="card text-white bg-secondary mb-3" id="total" style="max-width: 20rem;">
<div class="card-header">Header</div>
<div class="card-body">
<h4 class="card-title" id="total"></h4>
</div>
</div>
I get the following error
index.html:80 Uncaught (in promise) ReferenceError: Invalid left-hand
side in assignment at getWorldTotal
My question is what did i do wrong? Also is this the best way to update HTML when making api calls ?

The Document method getElementById() returns an Element object and you are trying to change it which gives you the error.
Source . Also, if you want to change the text you can use
innerText
const getWorldTotal = async () => {
const response = await fetch('https://cors-anywhere.herokuapp.com/https://health-api.com/api/v1/covid-19/total');
const worldTotal = await response.json();
alert(worldTotal.total_confirmed)
document.getElementById('total').innerText = worldTotal.total_confirmed
};
getWorldTotal()

try this:
const xURL = 'https://cors-anywhere.herokuapp.com/https://health-api.com/api/v1/covid-19/total'
, total = document.getElementById('total')
;
const getWorldTotal = async () => {
let data = await (await fetch(xURL)).json()
//console.log( 'data ', data)
total.textContent = data.total_confirmed
}
getWorldTotal()

As Rajesh and Mr Jojo stated, I think adding ".textContent" or ".innerText" after "document.getElementById('total')" will help with this.
Also, when calling the function, you can add a semicolon to end the statement. getWorldTotal() + ";". While this is optional, it can be good to get in the habit of 'strict'.

Related

React, component not re-rendering after change in an array state (not the same as others)

I'm trying to make a page that gets picture from a server and once all pictures are downloaded display them, but for some reason the page doesn't re-render when I update the state.
I've seen the other answers to this question that you have to pass a fresh array to the setImages function and not an updated version of the previous array, I'm doing that but it still doesn't work.
(the interesting thing is that if I put a console.log in an useEffect it does log the text when the array is re-rendered, but the page does not show the updated information)
If anyone can help out would be greatly appreciated!
Here is my code.
export function Profile() {
const user = JSON.parse(window.localStorage.getItem("user"));
const [imgs, setImages] = useState([]);
const [num, setNum] = useState(0);
const [finish, setFinish] = useState(false);
const getImages = async () => {
if (finish) return;
let imgarr = [];
let temp = num;
let filename = "";
let local = false;
while(temp < num+30) {
fetch("/get-my-images?id=" + user.id + "&logged=" + user.loggonToken + "&num=" + temp)
.then(response => {
if(response.status !== 200) {
setFinish(true);
temp = num+30;
local = true;
}
filename = response.headers.get("File-Name");
return response.blob()
})
.then(function(imageBlob) {
if(local) return;
const imageObjectURL = URL.createObjectURL(imageBlob);
imgarr[temp - num] = <img name={filename} alt="shot" className="img" src={imageObjectURL} key={temp} />
temp++;
});
}
setNum(temp)
setImages(prev => [...prev, ...imgarr]);
}
async function handleClick() {
await getImages();
}
return (
<div>
<div className="img-container">
{imgs.map(i => {
return (
i.props.name && <div className="img-card">
<div className="img-tag-container" onClick={(e) => handleView(i.props.name)}>{i}</div>
<div className="img-info">
<h3 className="title" onClick={() => handleView(i.props.name)}>{i.props.name.substr(i.props.name.lastIndexOf("\\")+1)}<span>{i.props.isFlagged ? "Flagged" : ""}</span></h3>
</div>
</div>
)
})}
</div>
<div className="btn-container"><button className="load-btn" disabled={finish} onClick={handleClick}>{imgs.length === 0 ? "Load Images" : "Load More"}</button></div>
</div>
)
}
I think your method of creating the new array is correct. You are passing an updater callback to the useState() updater function which returns a concatenation of the previous images and the new images, which should return a fresh array.
When using collection-based state variables, I highly recommend setting the key property of rendered children. Have you tried assigning a unique key to <div className="img-card">?. It appears that i.props.name is unique enough to work as a key.
Keys are how React associates individual items in a collection to their corresponding rendered DOM elements. They are especially important if you modify that collection. Whenever there's an issue with rendering collections, I always make sure the keys are valid and unique. Even if adding a key doesn't fix your issue, I would still highly recommend keeping it for performance reasons.
It is related to Array characteristics of javascript.
And the reason of the console log is related with console log print moment.
So it should be shown later updated for you.
There are several approaches.
const getImages = async () => {
... ...
setNum(temp)
const newImage = [...prev, ...imgarr];
setImages(prev => newImage);
}
const getImages = async () => {
... ...
setNum(temp)
setImages(prev => JOSN.parse(JSON.object([...prev, ...imgarr]);
}
const getImages = async () => {
... ...
setNum(temp)
setImages(prev => [...prev, ...imgarr].slice(0));
}
Maybe it could work.
Hope it will be helpful for you.
Ok the problem for me was the server was not sending a proper filename header so it was always null so the condition i.props.name was never true... lol sorry for the confusion.
So the moral of this story is, always make sure that it's not something else in your code that causes the bad behavior before starting to look for other solutions...

How to fetch API in JavaScript?

I have written a javascript to fetch API but it is not working can anyone please see that is there any error in my javascript. I have given some parts of my javascript which I think has error.
MY JAVASCRIPT
const redraw = () => {
resultEl.innerHTML = '';
const paged = pageResponse(results, getPageSize(), getCurrPage());
const contents = document.createElement('div');
contents.innerHTML = paged.map(record => `<div class='latestatus'><p class='copytxt'>${record.status}</p><div> <button class="copystatus btn">Copy</button></div></div>`).join('');
resultEl.append(contents);
};
//Fetch API
const retrieveAllStatus = async function() {
// write your asynchronous fetching here
// here we are making a network call to your api
const response = await fetch('https://goodman456.000webhostapp.com/api.php');
// then converting it to json instead of a readable stream
const data = await response.json();
// finally go over the array and return new object with renamed key
const results = data.map(val => ({val.status}));
return results;
}
Please just once visit the link below. It's my request.
https://goodman456.000webhostapp.com/api.php
I would make your work easy, My friends said that the below section
contents.innerHTML = paged.map(record => `<div class='latestatus'><p class='copytxt'>${record.status}</p><div> <button class="copystatus btn">Copy</button></div></div>`).join('');
resultEl.append(contents);
};
Especially the {$record.status} where I need the JSON data to be placed. My friend also said that there is something wrong in fetching API.
Please I have stucked here for a long time. And thanks in advance for those who answer this question.

Struggling to populate from a pair of API's in Vanilla JavaScript

Working on modifying a project I'm learning from.
The initial project is to create a sort of infinitely scrolling Twitter Clone. Posts were grabbed from https://jsonplaceholder.typicode.com/ api, and I'm trying to add another level by bringing in images from another image placeholder API.
I'm a noob, so I was able to successfully grab data from both API's and populate the DOM. Trouble is, with my current structure, I'm repeating placeholder images as what I'm grabbing from the placeholder api is in 5 object blocks. Could use some help in making sure every post has a different photo. Thanks, total newb here. Wondering if I should just be populating an array of objects and working from there, but maybe there's a shortcut I'm missing?
const postsContainer = document.getElementById("posts-container");
const loading = document.querySelector(".loader");
const filter = document.getElementById("filter");
let limit = 5;
let page = 1;
//Fetch Posts from API
async function getPosts() {
const res = await fetch(
`https://jsonplaceholder.typicode.com/posts?_limit=${limit}&_page=${page}`
);
const data = await res.json();
return data;
}
//Fetch Photos from another API
async function getPhoto(photo) {
const res = await fetch(`https://randomuser.me/api`);
const data = await res.json();
photo = data.results[0].picture.thumbnail;
return photo;
}
//Show items in DOM
async function showPosts() {
const posts = await getPosts();
const pic = await getPhoto();
posts.forEach((post) => {
const postEl = document.createElement("div");
postEl.classList.add("post");
postEl.innerHTML = `
<div class="number">
<img class="profile-pic" src="${pic}" alt="user photo" />
</div>
<div class="post-info">
<h2 class="post-title">${post.title}</h2>
<p class="post-body">
${post.body}
</p>
</div>
</div>
`;
postsContainer.appendChild(postEl);
});
}
//Show loader and fetch more posts
function showLoading() {
loading.classList.add("show");
setTimeout(() => {
loading.classList.remove("show");
setTimeout(() => {
page++;
showPosts();
}, 1000);
}, 300);
}
//Show initial posts
showPosts();
window.addEventListener("scroll", () => {
const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
if (scrollTop + clientHeight >= scrollHeight - 5) {
showLoading();
}
});
GitHub Repo: https://github.com/unsubstantiated-Script/infinite-scroller
TIA
Problem solved. Needed to move the pic variable inside my forEach loop. That and async the forEach loop.

Extracting value from an object

I'm working on a discord bot, using discord.js.
I've been working on this command for too long without finding a solution, so I come here to ask for help.
Here is my problem, maybe it's really simple to solve to you, and that would be great :D
I want to create a command that sends a random gif, based on a keyword.
I'm using a node module called giphy-random.
(async () => {
const API_KEY = "hidden";
const gif = await giphyRandom(API_KEY, {
tag: "kawaii"
});
console.log(gif)
}
I would like to be able to get only the value 'url' of the const which is defined by the function (i'm maybe wrong in my words, I'm a beginner) in order to send it in a channel.
You simply want gif.data.url In fact if you change your console.log like this:
console.log(gif.data.url);
You'll see the url printed to the console.
According to the docs, the link is returned in data.url property of the resulting object. So your code should look like:
(async () => {
const API_KEY = "hidden";
const gif = await giphyRandom(API_KEY, {
tag: "kawaii"
});
console.log(gif.data.url)
}
You can simply access field like this:
const API_KEY = "hidden";
const gif = await giphyRandom(API_KEY, {
tag: "kawaii"
});
const {url} = gif.data; // equal to const url = gif.data.url
console.log(gif);
}

How to properly fetch data from iTunes API?

So I'm trying to use vanilla JavaScript and do a fetch from iTunes' API to create a page that allows a user to type in an artist name and then compile a page with like 15 top results. I'm using the following for my fetch:
function dataPull() {
fetch("https://itunes.apple.com/search?term=")
.then(function(response) {
if (response.status !== 200) {
console.log(response.status);
return;
}
response.json().then(function(data){
console.log(data);
let returnResponse = document.createElement("div");
let input2 = inputElement.value;
for (let i=0; i<data.length; i++){
if (inputElement===data[i].artistName){
console.log(data[i].artistName);
returnResponse.innerHTML = `
<div class="box">
<img src=${artWorkUrl30} alt="Album Image">
<p><span>Artist Name:</span>${data[i].artistName}</p>
<p><span>Track: </span>${data[i].trackName}</p>
<p><span>Album Name: </span>${data[i].collectionName}</p>
<p><span>Album Price: </span>${data[i].collectionPrice</p>
</div>
`;
results.appendChild(returnResponse);
}}
console.log(data);
});
}
)
The function is being called in a click event and I'm sure I can put everything from "let returnResponse" down to the append in another function. The issue I'm having is actually getting the API to show ANY results. At the moment if I type in Bruno Mars, Beethoven, or U2 it's not logging any data and it's giving me "Provisional Headers are Shown" when I check out the the Status Code.
Any thoughts on what I could do to make this better/work?
For full code:
jsfiddle
Typical fetch call will look like this.
fetch(`${url}`)
.then(response => response.json())
.then(json =>
// do something with the json
)
Modify your code and see if you can console.log() anything of note.
I would reccomend seperating your concerns. Making the dataPull function just get the results. That means you can use this code at other places without changing it.
Here the function returns the json object as a promise.
function dataPull(search) {
return fetch("https://itunes.apple.com/search?term="+search).then(res => res.json());
}
No you can call the dataPull function and resolve the promise. You'll have the result and can do what you want with it.
dataPull("test").then(res => {
console.log(res.results);
/*
res.results.forEach(item => {
div and span magic here
})
*/
})
Here's a link to a working JSFiddle.
https://jsfiddle.net/14w36u4n/

Categories

Resources