Display results of an API request on HTML page using JavaScript - javascript

I have to build a page where the infos of countries (such as name, population, etc) are displayed using an API. I have managed to show the request results on the console using fetch, but I don't know how to display the results in the HTML page. I'm a beginner and very unexperienced. I know very little js.
I've seen other topics like this one, but they didn't really help solve my problem. One of them had an answer that suggested a code like the following, which worked fine until line 7 of the js script. However after adding the rest of the code I get an error that says Uncaught (in promise) TypeError: data is undefined. I don't understand why it says data is undefined when it has been used before.
function displayAll() {
let countriesList = [];
let url = "https://restcountries.com/v3.1/all";
fetch(url).then(function(response){
response.json().then(function(data) {
console.log(data); // works fine up until here
})
.then((data) => { // error says that 'data' is undefined
let countries = document.getElementById("countries-container");
data.results.forEach((item) => {
countriesList.push(item.name);
let div = document.createElement("div");
div.innerText = item.name;
countries.appendChild(div);
})
console.log(countriesList)
})
});
}
<body onload="displayAll()">
<header>Countries</header>
<div class="container" id="countries-container">
<!-- This is where the results will be displayed -->
</div>
<script src="./assets/scripts.js"></script>
</body>
I want to add new elements to serve as cards (one for each country).
Something tells me there will be more errors because the results printed in the console seem a bit too complicated to iterate, since it seems to be a matrix:
I'm not using any frameworks, since I still need to learn more about the basics before jumping into the more fancy stuff. The code is just HTML, CSS and JavaScript and I want to keep it that way if possible. I've tried learning React alreaddy and I think I'm not ready yet... Anyway, if anybody can help me with this, I'll be very grateful.

I've managed to solve the problem. Adding return data to the first .then solved the data undefined error, but then I got another error: TypeError: cannot read properties of undefined (reading forEach). This error disappeared after I deleted results from data.results.forEach
I could finally make the data appear in the HTML page, but it was shown as [object Object] and JSON.parse() would thow another error about an unexpected character somewhere in the original data. So I realized that I had to create the HTML elements to be able to show the data in the page. Obvious, I know. But as I said: I'm a total beginner.
So with that in mind, I created the following code and it works just fine!
Turns out I didn't really need a list of all the countries, so I eliminated that from the code.
// Searches and shows the data of all the countries in the homepage upon loading
function displayAll() {
let url = "https://restcountries.com/v3.1/all";
fetch(url).then(function(response){
response.json().then(function(data) {
console.log(data);
return data;
})
.then((data) => {
data.forEach((item) => {
showCountryHome(item);
})
})
});
}
// Creates a card for each country with the information I want
function showCountryHome(data) {
let countries = document.getElementById("countries-wrapper");
let div = document.createElement("div");
div.className = "card";
div.innerHTML = `<img src="${data.flags.svg}" width=200>
<p>${data.name.common}</p>
<p>Population: ${data.population}</p>
<p>Region: ${data.region}</p>
<p>Capital: ${data.capital}</p>`
countries.appendChild(div);
}

Related

Trying to display API Data in HTML - data.forEach is not a function

Could anyone please take a look, new to API and JavaScript really,
I am trying to display the thumbnail data from the API, however I keep getting the error below,
TypeError: data.forEach is not a function
at index.js:9:18
at async comics (index.js:4:22)
Having read and watched a lot trying to figure it out, I thought I'd reach out to see if someone could show me and explain what I'm doing wrong.
currently using vanilla JS and have changed the key for this question, however consle.log shows data, I just cant make it appear in HTML.
async function comics() {
const urlComic = await fetch("https://gateway.marvel.com:443/v1/public/comics?limit=100&apikey=85848598594594")
.then(result => {
return result.json();
})
.then(data => {
data.forEach(comic => {
const comicBook = `<img src=${comic.thumbnail} >`;
document.querySelector(".imgContainer").insertAdjacentHTML("afterbegin", comicBook);
});
})
.catch(error => console.log(error));
}
comics()
I have tried researching as to why this isn't working but can't find the correct solution or tip to help me figure it out.
I am looking to generate the thumbnail data into an <img>

How can I display the snapshot data in HTML?

I'm trying to display the snapshot data from the database to the html page, but it seems to display an '[object Object]'instead of the gmail.
I'm new to code so please be patient.
here is the code:
firebase.database().ref('gmails/').get().then((snapshot) => {
if (snapshot.exists()) {
console.log(snapshot.val());
var content = '';
// give each message a unique ID
content += "<li>";
content += snapshot.val();
content += "</li>";
document.getElementById("gmails").innerHTML += content;
} else {
console.log("No data available");
}
}).catch((error) => {
console.error(error);
});
THE HTML:
<ul id="gmails">
</ul>
enter image description here
In the image you can see the object instead of the value
It sounds like you have a javascript Object which contains data that you want to render as text on your page. When you see [object Object] it's a sign that you're trying to render something as text that your code doesn't know how to turn into text, in this case your snapshot object.
There are a few simple things you can try / questions you can answer for yourself:
What is the "shape" of your snapshot object? Do you know the names of variables it contains? Are they supposed to be strings? Is it wrapping HTML of some kind? If so, you'll probably want to render either specific strings inside the object or one big string contained inside. If it's HTML I believe you can just insert it the way you already are.
If you don't know the structure of the contents of snapshot, there are some easy ways to figure it out:
If you know how to use the Chrome debugger ("source" tab of the dev tools, ctrl-P or command-P to search for your relevant file, and click on the line number to add a breakpoint), put a breakpoint on console.log(snapshot.val()); and inspect the value of snapshot. You can hover over it and click into its child-objects, and determine their names and structure for accessing and finding the strings you want to display
If you want a simple solution without tools, you can change console.log(snapshot.val());
...to:
console.log(JSON.stringify(snapshot));
...and see how your data is structured as JSON. That will just drop the whole object into your console, which I assume is just displaying `[object Object] as-is.
Once you have that figured out, you should be able to access the right children of snapshot that contain the text you're trying to render.

My react component is failing due to component rendering before state is set. How can I resolve this issue?

I don't know if what I'm trying to do is possible but I've been trying for a week now and I feel like I'm so close but I just can't get there. Maybe it's not possible? Anyway, using reactjs and next js (I'm new to coding so I'll try my best to explain clearly what I'm trying to do):
I have a webapp that shows user transactions (from an api that I don't own/didn't create). I added like/ comment functionality to this app using firestore. Basically every time someone comments or likes a post their username and like/comment get's stored in my database along with the post id (which came originally from the api - which again - I didn't create). I thought it would be nice to let users know when someone likes or comments on their transaction and the way I planed to do this was like this :
First, query (my database - firestore) all posts that have a like or a comment, then set that post_ID in state
Next, I'll loop through all of those post_ID's and use them to complete a URL for an api fetch. You see, the api ends like the /sales/{saleID} .... which sale ID is the same as my post ID but the name varies because I changed it for my data base. That fetch will return a bunch of arrays , each of which show a seller/buyer.
Then I can take each buyer and seller and create a notification that says something like "hey {seller} {buyer}, someone liked your post. And I would only show this message if it's the current user and the current user matches the buyer or seller.
So part 3 I haven't done yet but I'm pretty sure I can pull off - I've done something similar. Part 1 seems to be working great! Part 2 is where I think I'm failing. I keep getting a "failed to fetch" but I think this is because some of the arrays are returning empty. Could you guys help me by reviewing my code and letting me know what you think? Like I said, I'm new, so I'm sure I wrote a lot of dumb stuff in there but this is a work in progress and a lot of stuff I did was me trying things out. Here is the code:
Also, here are some issues I've identified:
when I console.log(posts)- It returns an empty array twice, then it returns the array of postsID's but multiple times. Sometimes 3 times, sometimes 7 times. This number seems to vary though but 3 and 7 are what I keep seeing.
when I console.log(postID)- same idea
when I console.log(postData)- very similar. I get an empty array a couple of time, then I get an array for the post ID. Here is the strange thing. Ideally, this is supposed to contain an array of transaction info for each post ID that was used, but instead I get an empty array, then another, then my transaction arrays start coming in but a lot are duplicates.
-So seems to me that the issue is at the very beginning, the postID's being returned so many times.
I also found something else. If I comment everything out in the return and just put some dummy text, and then I console log postData (which is the most important item), then everything seems to work perfectly: I get an empty array a time or two then I get on array listed per post ID. So I'm thinking that the issue is that this component is failing because it's crashing before it's done rendering. So it's trying to return something that's not there yet (the postData.map....)
function UserNotifications() {
const [posts, setPosts] = useState([]);
const [postData, setPostData] = useState([]);
const postID = posts.map((post) => post.data().likePostID);
//------------ STEP 1: GET DATA FROM FIREBASE AND USE DATA ON API -------------------//
useEffect(() => {
onSnapshot(
query(collection(db, 'Feed Posts'), orderBy('timestamp', 'desc')),
(snapshot) => setPosts(snapshot.docs)
);
}, []);
useEffect(() => {
if (posts.length != 0) {
postID.map(async (likePostID) => {
const response = await fetch(
`https://proton.api.atomicassets.io/atomicmarket/v1/sales/${likePostID}`
);
const { data } = await response.json();
setPostData(data);
});
}
}, [posts]);
console.log(postData);
//----------------------------------- STEP 2: RETURN ----------------------------------//
return (
<>
{' '}
notifications coming soon
{/* {postData.map((result) => {
const { buyer, seller } = result;
if (seller || buyer) {
return <> hello {buyer}</>;
}
})} */}
</>
);
}
export default UserNotifications;
Rendering virtually always happens multiple times in React, and it is up to you to prevent issues caused by uninitialized data, which is the case here.
A simple way to do so is by adding another return, just above the return that you already have, as follows:
if (!postData)
return null;
You need to do this for all variables that can be empty (or otherwise invalid) at any time during rendering.

Refilling a form from a database

I'm so stuck on this I might not even be able to formulate a sensible question, but here goes...
I have a gigantic (and occasionally changing) form. I've found a reasonable way to get all the data from the form, turn it into an object, and save it to Firebase all at once. It looks like this, and is working fine (I think):
const incidentReport = document.getElementById('incident-report-form');
let irv = {};
// This works. All form data is saved to an object (as required by firebase), with the question as the name and the answer as the value.
incidentReport.addEventListener('submit', (e) => {
e.preventDefault();
[...incidentReport.elements].forEach((item) => {
let name = item.name;
let value = item.value;
irv = { ...irv, [name]: value };
});
// After all data is collected in one object, I send it to the database all at once.
db.collection('incident reports').add(irv);
});
Okay, so far so good... Now I want to get it back out of the database (I know how to do this) and repopulate the same form (no idea). I'm 100% stumped and I don't even know what to try.
Please forgive me if this is super easy and my brain is just shutting off... it's been a rough day.
Thanks in advance.
EDIT - This seems to work? I'm still very open to criticism and/or improvements.
// Get data from incident reports
//#TODO -> Need to create a list of incident reports, and then load the one //the user clicks on.
//Right now there is only one incident report in the database for testing.
db.collection('incident reports')
.get()
.then((snap) => {
snap.docs.forEach((element) => {
data = element.data(); //Previously declared but not included in this snippet, sorry.
});
for (let [key, value] of Object.entries(data)) {
let x = document.getElementsByName(key)[0];
if (x !== undefined) {
x.value = value;
}
}
});
If I understood it correctly, once you returned the data from your Firestore collection, you want to print them back in your HTML form. Considering that, it should not be very hard for you to achieve that.
Once you load the documents into an array, you should be able to assign the values to variables, that will be printed in the form. It should be something like this:
//Getting the collection and a specific document
var report = db.collection('incident reports').doc('<report>');
var getDoc = report.get()
.then(doc => {
if (!doc.exists) {
console.log('No such document!');
} else {
// Loading the values of the document into variables
var name = getDoc.data().name;
var value = getDoc.data().value;
...
// Other values loaded to other variables that you create
}
})
.catch(err => {
console.log('Error getting document', err);
});
Once you have loaded the values into variables, you just need to create a tag <script> that will be adding the values via Javascript into your HTML. Something that can look like this:
<script src="http://code.jquery.com/jquery-3.4.1.min.js"></script>
document.getElementById('<form item name>').innerHTML = name;
</script>
While this code is not tested, I believe it should be a good starting point for you, on what you need to do, to achieve your goal. It's only for one document, but since you are on tests right now and have only one document, you should be fine.
Besides that, you can find a good and full example on retrieving values from Firestore and priting in a page, in this other post here: How can I display all data from Firestore documents into html elements
Let me know if the information helped you!

Firestore - Query, then update

I want to return an item with a specific ID and perform an update operation on it. My query gets the right result, but it won't let me update it.
I tried following this tutorial: https://www.youtube.com/watch?v=mYyPbfpoZeM
And read the documentation. Both didn't help. Other threads to the same topic are, well, different.
I have a database of objects which have a unique ID stored as integer.
I have an HTML form to get an ID as user input and the query below to retrieve the according object.
I tried this. The query worked, the update didn't.
db.collection('objects').where('ID','==', ID ).get().then((snapshot) => {
snapshot.docs.forEach( doc => {
console.log('debug');
console.log(doc.data().ID);
})
});
I am still new to firebase and js, so please forgive me if my code is uterly wrong.
I am currently stuck with this:
db.collection('objects').where('ID','==', ID ).get().then((doc) => {
console.table(doc);
});
Which is still not working.
For the second snippet an I currently get an unlegible table in which I can't really find the object I was looking for.
How do I update a single value in a single document?
EDIT: I forgot my implementation attempts of the update function.
I tried doc.update({value:0}) inside the for loop in snippet one which yielded doc.update is not a function. Similarly for doc.data().update(...).
In the second snippet I mainly tried to see what I got returned and ran variations of the above mentioned uodate function. With no success.
I managed to get it to work by studying the part of the firestore documentation that goes more into detail about the actual functions. Somehow it was hard for me to find this.
db.collection("users").where("name", "==", somename).limit(1).get().then(query => {
console.log(query);
const thing = query.docs[0];
console.log(thing.data());
let tmp = thing.data();
tmp.current_game_play = tmp.current_game_play + 1;
console.log(tmp);
thing.ref.update(tmp);
});
So I use where to get a Query object, use get to get a a querySnapshot inside the then promise resolve, use docs[0] to retrieve the first (and only) documentSnapshot and finally ref to get a reference that makes the whole thing updatable later.
try this:
var objectRef= db.collection("objects").doc(ID);
objectRef.update({
value: 0
}).then(function() {
console.log("Document successfully updated!");
}).catch(function(error) {
// The document probably doesn't exist.
console.error("Error updating document: ", error);
});

Categories

Resources