Get all data from api and insert into HTML - javascript

I have 7 cards in my html, with an image, title, description and source column. I'm trying to get the data from gnews api and then populate my cards with the data i get from the api. I'd like the data from the api to swap out my placeholder texts and image. But i'm only able to swap out the details in the first card in my HTML.
The JSON from the API look like this:
"articles": [
{
"title": "xxx xxx",
"description": "xxx xxx xxx",
"content": "xxx xxx xxx xxx... [1514 chars]",
"url": "xxx xxx",
"image": "xxx.jpg",
"publishedAt": "xxx",
"source": {
"name": "xxx",
"url": "xxx.com/"
}
}
]
I tried a forEach but it got only the first card
const title = document.querySelectorAll(".title"),
image = document.querySelector(".image"),
source = document.querySelector(".source"),
url = document.querySelector(".url");
.........
.then(function(data){
data.articles.forEach(article => {
title.innerHTML = article.title;
image.style.backgroundImage = article.image;
source.innerHTML = article.source.name;
url.setAttribute('href', article.url);
url.setAttribute('target', '_blank');
});
}
// And also i tried to target every card individually which worked but that means i would have
// to target all 7 html cards that i have which would be quite cumbersome and repetitive to write.
// Below is the code for the individual targetting..
news.title = data.articles[0].title;
news.image = data.articles[0].image;
news.source = data.articles[0].source.name;
news.url = data.articles[0].url;
news.description = data.articles[0].description;
How can i write the code to be able to get data from all the articles JSON and to fill up all the other cards with different news concurrently??

Hi and welcome to the community.
It looks like you still have a great work to go.
Well, you must first think this one through: you have to iterate through all of the cards and all of the components, which is something you are not doing.
That would mean something like:
.then(function(data){
data.articles.forEach(article => {
title.innerHTML = article.title;
image.style.backgroundImage = article.image;
source.innerHTML = article.source.name;
url.setAttribute('href', article.url);
url.setAttribute('target', '_blank');
//some code to skip to another card
});
Keep in mind that
const title = document.querySelectorAll(".title"),
image = document.querySelector(".image"),
source = document.querySelector(".source"),
url = document.querySelector(".url");
all of these are retrieving arrays of elements, since you have seven of them, right?
In your code you keep on pointing to image, title source and url, whith no indication of index. If that's the case, you are constantly updating the first.
Try to do this:
.then(function(data){
let x=0;
data.articles.forEach(article => {
title[x].innerHTML = article.title;
image[x].style.backgroundImage = article.image;
source[x].innerHTML = article.source.name;
url[x].setAttribute('href', article.url);
url[x].setAttribute('target', '_blank');
x++
});
It's not a perfect solution, though.
Take a look at this page and read it carefully. Take a few time to do it - I did it! If you still don't got it, let me know!

Related

How to fix Javascript associative array error

I am trying to display a list of images with their titles stored in an associative array. But the code only displays the last image and title in the array, in the browser not all of them. However when I console log the values: value.title and value .image the full list is displayed in the console. I must be missing something simple any pointers would be welcome.
<center id="pics"></center>
<script>
const photos = [
{
title: "Landscape River",
image: "landscape1.png",
},
{
title: "Landscape Mountains",
image: "landscape2.png",
},
{
title: "Landscape Mountain Road",
image: "landscape3.png",
},
{
title: "Landscape Hills and Lake",
image: "landscape4.png",
},
];
photos.forEach((value) => {
console.log(value.title, value.image);
document.getElementById("pics").innerHTML =
`<img src="images/${value.image}" >` + "<br>" + value.title;
});
</script>
</body>
While the accepted answer kind of works, it is a not a good solution, because it leads to totally unnecessary re-rendering of the DOM with every loop iteration. And that is just the performance side of the story; using innerHTML also is bad security-wise.
Instead, create those elements dynamically using document.createElement, append it to a documentFragment, and when the loop is done, append that fragment to the actual DOM.
That being said, this is what a proper solution could look like:
const picsContainer = document.getElementById("pics");
const fragment = new DocumentFragment();
photos.forEach(({image, title}) => {
const img = document.createElement('img');
img.src = `images/${image}`;
const br = document.createElement('br');
const text = document.createTextNode(title);
fragment.append(img, br, text);
});
picsContainer.append(fragment);
You will want to do document.getElementById("pics").innerHTML += instead of just =. You want to append each title and image, and not reset the innerHTML every time with a new title/image if that makes sense. Happy coding!

Function returning object instead of Array, unable to .Map

I'm parsing an order feed to identify duplicate items bought and group them with a quantity for upload. However, when I try to map the resulting array, it's showing [object Object], which makes me think something's converting the return into an object rather than an array.
The function is as follows:
function compressedOrder (original) {
var compressed = [];
// make a copy of the input array
// first loop goes over every element
for (var i = 0; i < original.length; i++) {
var myCount = 1;
var a = new Object();
// loop over every element in the copy and see if it's the same
for (var w = i+1; w < original.length; w++) {
if (original[w] && original[i]) {
if (original[i].sku == original[w].sku) {
// increase amount of times duplicate is found
myCount++;
delete original[w];
}
}
}
if (original[i]) {
a.sku = original[i].sku;
a.price = original[i].price;
a.qtty = myCount;
compressed.push(a);
}
}
return compressed;
}
And the JS code calling that function is:
contents: compressedOrder(item.lineItems).map(indiv => ({
"id": indiv.sku,
"price": indiv.price,
"quantity": indiv.qtty
}))
The result is:
contents: [ [Object], [Object], [Object], [Object] ]
When I JSON.stringify() the output, I can see that it's pulling the correct info from the function, but I can't figure out how to get the calling function to pull it as an array that can then be mapped rather than as an object.
The correct output, which sits within a much larger feed that gets uploaded, should look like this:
contents:
[{"id":"sku1","price":17.50,"quantity":2},{"id":"sku2","price":27.30,"quantity":3}]
{It's probably something dead simple and obvious, but I've been breaking my head over this (much larger) programme till 4am this morning, so my head's probably not in the right place}
Turns out the code was correct all along, but I was running into a limitation of the console itself. I was able to verify this by simply working with the hard-coded values, and then querying the nested array separately.
Thanks anyway for your help and input everyone.
contents: compressedOrder(item.lineItems).map(indiv => ({
"id": indiv.sku,
"price": indiv.price,
"quantity": indiv.qtty
}))
In the code above the compressedOrder fucntion returns an array of objects where each object has sku, price and qtty attribute.
Further you are using a map on this array and returning an object again which has attributes id, price and quantity.
What do you expect from this.
Not sure what exactly solution you need but I've read your question and the comments, It looks like you need array of arrays as response.
So If I've understood your requirement correctly and you could use lodash then following piece of code might help you:
const _ = require('lodash');
const resp = [{key1:"value1"}, {key2:"value2"}].map(t => _.pairs(t));
console.log(resp);
P.S. It is assumed that compressedOrder response looks like array of objects.

Code is not displaying JSON data

Hey guys I am trying to make a request to a JSON page, grabbing the data, then displaying it to my console but it is giving me "undefined". Why is that?
Here is the code and then the JSON page will be posted under it:
(function Apod() {
var api_key = 'NNKOjkoul8n1CH1NoUFo',
url = 'https://api.nasa.gov/planetary/apod' + "?api_key=" + api_key,
data;
var apodRequest = new XMLHttpRequest();
apodRequest.onreadystatechange = function() {
if (apodRequest.readyState === 4 && apodRequest.status === 200) {
var response = apodRequest.responseText;
var parsedAPOD = JSON.parse(response);
data += parsedAPOD;
for (i = 0; i < parsedAPOD.length; i++) {
data += parsedAPOD[i];
console.log("Parsing lines: <br>" + parsedAPOD[i]);
}
}
apodRequest.open("GET", url, true);
apodRequest.send(null);
}
}());
JSON page parsing:
{
"date": "2016-11-05",
"explanation": "Shot in Ultra HD, this stunning video can take you on a tour of the International Space Station. A fisheye lens with sharp focus and extreme depth of field provides an immersive visual experience of life in the orbital outpost. In the 18 minute fly-through, your point of view will float serenely while you watch our fair planet go by 400 kilometers below the seven-windowed Cupola, and explore the interior of the station's habitable nodes and modules from an astronaut's perspective. The modular International Space Station is Earth's largest artificial satellite, about the size of a football field in overall length and width. Its total pressurized volume is approximately equal to that of a Boeing 747 aircraft.",
"media_type": "video",
"service_version": "v1",
"title": "ISS Fisheye Fly-Through",
"url": "https://www.youtube.com/embed/DhmdyQdu96M?rel=0"
}
You have a few errors in your code.
First off, the general structure of it should be like this
(function Apod() {
var api_key = 'NNKOjkoul8n1CH1NoUFo',
url = 'https://api.nasa.gov/planetary/apod' + "?api_key=" + api_key,
data;
var apodRequest = new XMLHttpRequest();
apodRequest.onreadystatechange = function() {
//Code here
};
apodRequest.open("GET", url, true);
apodRequest.send(null);
}());
Notice how I moved apodRequest.open("GET", url, true); and apodRequest.send(null); outside of the onreadystatechange handler.
Secondly, instead of
apodRequest.onreadystatechange = function() {
if (apodRequest.readyState === 4 && apodRequest.status === 200) {
//Code here
}
}
you can simply do
apodRequest.onload = function() {
//Code here
};
As it's the event that will fire when a response is returned. So you don't need the if check inside.
Finally, inside the onload handler, you have a few mistakes, such as:
data += parsedAPOD; this is wrong because data is an object undefined up to this point and parsedAPOD is an object. Doing += between two objects will not merge them. If you want to merge two objects there are other ways, e.g. Object.assign
for (i = 0; i < parsedAPOD.length; i++) { ... } is wrong because parsedAPOD is an object. Objects do not have a length property, so this is not the correct way to iterate over it. Use for ... in ... loop instead
data += parsedAPOD[i]; is, again, wrong, because this is not the way to merge objects.
parsedAPOD[i] is wrong because i is an integer, in this case, so parsedAPOD[i] is simply undefined.
Hope this analysis helps you correct your code.
first of all parsedAPOD is an object and parsedAPOD.length is not valid. You can use for in loop to iterate through an object as below.
for (var i in parsedAPOD) {
data += parsedAPOD[i];
console.log("Parsing lines: <br>" + parsedAPOD[i]);
}

Randomize text, embed codes and URL's from list

I have a list with movie titles, youtube URL's (with which I can construct an embed code) and URL's to IMDB. On every page refresh, another movie title, Youtube video, and text with a URL to IMDB has to appear.
["Movie A", "URL_to_youtube_movie_A", "URL_to_IMDB_movie_A"],
["Movie B", "URL_to_youtube_movie_B", "URL_to_IMDB_movie_B"],
etc.
My website already has a refresh button: the page reloads with . How can I make the youtube video displayed randomized? I want the output to be HTML, so I can add elements afterwards, if necessary.
Shuffle the array, you can use underscore, or write custom function:
list = _.shuffle(list)
then output first n movies. This is the simplest method, that I think will be good enough for your case.
I would make an array of objects. Movie is an object, like this:
var list = [{ title: "Movie A", urlYouTube: "URL_to_youtube_movie", urlImdb: "URL_to_IMDB_movie_A"}, ...]
Also if you plan to do more operations than just show the random movies look at some javascript frameworks(backbone.js, angular, ...).
I would recommend you to use templates for the HTML output. Underscore also has simple template implementation. _.template(templateString, [data], [settings])
Something like this: DEMO && CODE
With simple javascript without any Library
You will need suffle function like below
DEMO
function arrayShuffle(oldArray) {
var newArray = oldArray.slice();
var len = newArray.length;
var i = len;
while (i--) {
var p = parseInt(Math.random()*len);
var t = newArray[i];
newArray[i] = newArray[p];
newArray[p] = t;
}
return newArray;
};
Call it like
var list = [{ title: "Movie A", urlYouTube: "URL_to_youtube_movie_A", urlImdb: "URL_to_IMDB_movie_A"},
{ title: "Movie B", urlYouTube: "URL_to_youtube_movie_B", urlImdb: "URL_to_IMDB_movie_B"},
{ title: "Movie C", urlYouTube: "URL_to_youtube_movie_C", urlImdb: "URL_to_IMDB_movie_C"}];
var Suffledlist = arrayShuffle(list);
And then show top 2 or 5 elements

Create JSON from jQuery each loop

All the questions I have dug through in the boards aren't really answering a question I have. So I will ask the experts here. First off, thank you very much for reading on. I really appreciate what Stackoverflow is all about, hopefully I can contribute now that I am a member.
I want to dynamically create a JSON object based off variables set from another JSON object from with a jQuery each loop. I think my syntax and probably my knowledge of this stuff is a little off.
I would like to end up with the following JSON structure:
{
desktop:{
title:300,
rev:200
}
}
Where "desktop" is a value from another JSON object not in this loop, I can call that no problem, in fact it is actually the name value I set on the other JSON object. I am looping through an array in the object called columns but want to set a separate object containing all the widths because the columns are adjustable and accessible via another frame that I will push it to, I want to retain those widths.
I was trying to do this from within the loop:
var colWidths = {};
$.each(columns, function(i) {
colWidths.desktop.title = columns[i].width;
});
I can alert columns[i].width successfully. The issue I have is creating and accessing this. Everything I seem to be doing seems right but this is not the case. Maybe its me or my setup? Could you please show me how to code this properly? OR I could create a Javascript Object if this is not possible. Thanks in advance!
Welcome to Stackoverflow. You did not write any error messages you got, so I assume the following.
// prepare the object correctly first
var colWidths = {
desktop: {
title: 0
}
};
// then ADDING each value with += instead of =
// (because in your code you will just have the last value)
$.each(columns, function(i) {
colWidths.desktop.title += columns[i].width;
});
EDIT
var grid = {
"name": "desktop",
"columns": [
{
"id": "icons",
"width": 50},
{
"id": "title",
"width": 200},
{
"id": "name",
"width": 300},
{
"id": "revision",
"width": 400}
]
};
var columns = grid.columns;
var gridName = grid.name;
var colWidths = {};
// CHANGE HERE
colWidths[gridName] = {};
$.each(columns, function(c) {
var col = columns[c];
var colname = col.id;
var colwidth = col.width;
// CHANGE HERE
var thisGrid = colWidths[gridName];
if(!thisGrid[colname]) thisGrid[colname] = 0;
thisGrid[colname] += colwidth;
});
//alert(colWidths.desktop.title);​
document.write(JSON.stringify(colWidths));
// RESULT:
// {"desktop":{"icons":50,"title":200,"name":300,"revision":400}}

Categories

Resources