I'm using newsapi to request JSON data, and am then dynamically loading it onto the page without reloading the page/going onto another page.
When the user initially goes onto the site, a request made on the backend will automatically be made and load the results onto the site via an EJS template. There will also be a button at the bottom of the page, so when a user clicks on it, new articles will be loaded.
The issue is that when the user clicks on the button, the new articles aren't appended after the last instance of a card-container. For example, say I have articles 1 2 3 4 5 already on the page and want to load articles 6 7 8 9, after clicking the button the articles are now in the order of 1 6 2 7 3 8 4 9 5. Where I want it to be in the order 1 2 3 4 5 6 7 8 9.
I've thought by using Jquerys insertAfter() function to insert each new element after the last would work, but it clearly doesn't.
Whilst the code I have below may be messy, I want to fix the logic before tidying it up.
JS
let more = document.getElementById("test");
more.addEventListener("click", function () {
(async () => {
const data = await fetch('http://localhost:3000/articles/');
const articles = await data.json()
for (let i = 0; i < articles.articles.length; i++) {
let newDate = articles.articles[i].date;
newDate = newDate.substring(0, newDate.indexOf('T')).split("-");
var articleList = document.getElementsByClassName("card-container");
var lastArticle = articleList[articleList.length - 1];
let cardContainer = document.createElement('div');
cardContainer.className += "card-container";
let card = document.createElement('div');
card.className += "card";
let content = document.createElement('div');
content.className += "content";
let thumbnail = document.createElement('div');
thumbnail.className += "thumbnail";
let image = document.createElement('img');
image.className += "image";
let text = document.createElement('div');
text.className += "text";
let title = document.createElement('div');
title.className += "title";
let a = document.createElement('a');
let meta = document.createElement('div');
meta.className += "meta";
let source = document.createElement('div');
source.className += "source";
let date = document.createElement('div');
date.className += "date";
document.getElementsByClassName('card-container')[i]
.appendChild(card).appendChild(content).appendChild(thumbnail)
.appendChild(image)
document.getElementsByClassName("content")[i]
.appendChild(text).appendChild(title).appendChild(a)
document.getElementsByClassName("text")[i]
.appendChild(meta).appendChild(source)
document.getElementsByClassName("meta")[i]
.appendChild(date)
let container = document.getElementById('article-container')
container.innerHTML = container.innerHTML + cardContainer;
image.setAttribute("src", articles.articles[i].image)
a.setAttribute('href', articles.articles[i].link);
a.innerHTML = articles.articles[i].title;
source.innerHTML = articles.articles[i].source.name;
date.innerHTML = newDate[1] + " " + newDate[2] + " " + newDate[0];
}
})();
})
Desired markup
<div class="card-container">
<div class="card">
<!-- Post-->
<div class="content">
<!-- Thumbnail-->
<div class="thumbnail">
<img
src="https://ssio.azurewebsites.net/x500,q75,jpeg/http://supersport-img.azureedge.net/2019/8/Man-City-190804-Celebrating-G-1050.jpg" />
</div>
<!-- Post Content-->
<div class="text">
<div class="title"><a
href="https://www.goal.com/en-gb/lists/deadline-day-dybala-coutinho-premier-league-transfers-happen/68rpu0erk0e81pm2anfv2ku16">Coutinho
llega a un acuerdo con el Arsenal para marcharse del Barcelona - PASIÓN
FUTBOL</a>
</div>
<div class="meta">
<div>Source</div>
<div class="date-text">07 07 2019</div>
</div>
</div>
</div>
</div>
</div>
JS Fiddle
I seem to have got it working - but not all of the JSON (other than the image) are being mapped to their divs inner HTML :/
https://jsfiddle.net/georgegilliland/ofxtsz2a/5/
In order to append in pure JS you have to take the last content of the container, append new data to it, then replace the container content with the new data.
I wrote a jsfiddle based on the stack overflow question I posted in the comment : https://jsfiddle.net/HolyNoodle/bnqs83hr/1/
var container = document.getElementById('container')
for(var i = 0; i < 3; i++) {
container.innerHTML = container.innerHTML + "<p>" + i + "</p>"
}
Here you can see I am getting the container inner html, appending new value to it, then replacing the container inner html by the new html
Fixed the issue... The problem was that I was getting elements by class name at whatever index the for loop was on. So if the for loop was on it's 5th iteration, it was appending content to the 5th instance of content, rather than appending it to the end of the container.
document.getElementById('article-container')
.appendChild(cardContainer)
.appendChild(card).appendChild(content).appendChild(thumbnail)
.appendChild(image)
document.getElementsByClassName("content")[i]
.appendChild(text).appendChild(title).appendChild(a)
document.getElementsByClassName("text")[i]
.appendChild(meta).appendChild(source)
document.getElementsByClassName("meta")[i]
.appendChild(date)
What I did to fix this was get the number of elements with the classname card-container before the for loop:
let nodelist = document.getElementsByClassName("card-container").length;
And then get elements at the index of the for loop summed with the amount nodelist.
document.getElementById('article-container')
.appendChild(cardContainer)
.appendChild(card).appendChild(content).appendChild(thumbnail)
.appendChild(image)
document.getElementsByClassName("content")[i + nodelist]
.appendChild(text).appendChild(title).appendChild(a)
document.getElementsByClassName("text")[i + nodelist]
.appendChild(meta).appendChild(source)
document.getElementsByClassName("meta")[i + nodelist]
.appendChild(date)
Related
I have this simple code with 5 paramaters taken from an API that logs data:
for (i = 0; i < arr.length-1; i++) {
console.log('For Calls')
console.log(arr[i].league.name)
console.log(arr[i].teams.home.name, arr[i].goals.home)
console.log(arr[i].teams.away.name, arr[i].goals.away)
}
it logs this data to the console (2 sets of data shown):
Logged Data
The issue I am having is trying to display this looped content to the website, I haven't even been able to get it on the screen so far using the .append methods.
Here is the format I am trying to create:
<div class="parentDiv">
<div class="league">Data goes here</div>
<div class="team1">Data goes here</div>
<div class="score1">Data goes here</div>
<div class="team2">Data goes here</div>
<div class="score2">Data goes here</div>
</div>
I am aware I can give each div a class and append that way but I need this in a loop so those methods do not work for me in this circumstance.
Any Tips are Appreciated.
My current attempt:
for (i = 0; i < filtered.length-1; i++) {
let parent = document.createElement("div")
parent.className = 'parentDiv'
let homeTeamName = document.createElement("div")
homeTeamName.className = 'league'
homeTeamName.innerHTML = filtered[i].league.name
parent.appendChild(homeTeamName)
let homeTeamScore = document.createElement("div")
homeTeamScore.className = 'team1'
homeTeamScore.innerHTML = filtered[i].teams.home.name
parent.appendChild(homeTeamScore)
let awayTeamName = document.createElement("div")
awayTeamName.className = 'score1'
awayTeamName.innerHTML = filtered[i].teams.home.name
parent.appendChild(awayTeamName)
let awayTeamScore = document.createElement("div")
awayTeamScore.className = 'team2'
awayTeamScore.innerHTML = filtered[i].teams.home.name
parent.appendChild(awayTeamScore)
}
It prints nothing to the dom, blank page. You can use the web console at footballify.net/test
You never Attach the "parent" variable to your body
Try:
document.body.append(parent) at the end
I'm a beginner in JavaScript. I've got a problem.
I need to create some elements and I need to put my API's data is these elements. But I want to create 3 cards (bootstraps) in my first row and 2 in my second row.
But I think my loop isn't ok. Because all my data are on my fifth card.
That's my code HTML and JavaScript:
HTML :
</section>
<section class="container">
<div class="row">
<div id="colCam1" class="col-12 col-lg-4"></div>
<div id="colCam2" class="col-12 col-lg-4"></div>
<div id="colCam3" class="col-12 col-lg-4"></div>
</div>
<div class="row">
<div id="colCam4" class="col-12 col-lg-4"></div>
<div id="colCam5" class="col-12 col-lg-4"></div>
</div>
</section>
JS :
fetch("http://localhost:3000/api/cameras")
.then((response) =>
response.json().then ((data) => {
console.log(data);
for(i=0; i < data.length; i++) {
let indexCard = document.createElement("div");
let indexImg = document.createElement("img");
let indexBodyCard = document.createElement("div");
let indexProductTitle = document.createElement("h5");
let indexProductPrice = document.createElement("p");
colCam1.appendChild(indexCard);
colCam2.appendChild(indexCard);
colCam3.appendChild(indexCard);
colCam4.appendChild(indexCard);
colCam5.appendChild(indexCard);
indexCard.classList.add("card");
indexCard.appendChild(indexImg);
indexImg.classList.add("card-img-top");
indexCard.appendChild(indexBodyCard);
indexBodyCard.classList.add("card-body");
indexBodyCard.appendChild(indexProductTitle)
indexProductTitle.classList.add("card-title");
indexBodyCard.appendChild(indexProductPrice);
indexProductPrice.classList.add("card-text");
indexProductTitle.innerHTML = data[i].name;
indexProductPrice.innerHTML = parseInt(data[i].price) + " €";
indexImg.setAttribute("src", data[i].imageUrl);
}
})
);
That's the result on my inspector :
Result of my code
Thx for your help
If I understood correctly, you are only expecting to get 5 elements from your API and you want to put each of them in one column. If that's the case, you can put your column elements in an array and index them accordingly in your loop like so:
const cols = [colCam1, colCam2, colCam3, colCam4, colCam5]
for(i=0; i < data.length; i++) {
let indexCard = document.createElement("div");
let indexImg = document.createElement("img");
let indexBodyCard = document.createElement("div");
let indexProductTitle = document.createElement("h5");
let indexProductPrice = document.createElement("p");
cols[i].appendChild(indexCard);
indexCard.classList.add("card");
indexCard.appendChild(indexImg);
indexImg.classList.add("card-img-top");
indexCard.appendChild(indexBodyCard);
indexBodyCard.classList.add("card-body");
indexBodyCard.appendChild(indexProductTitle)
indexProductTitle.classList.add("card-title");
indexBodyCard.appendChild(indexProductPrice);
indexProductPrice.classList.add("card-text");
indexProductTitle.innerHTML = data[i].name;
indexProductPrice.innerHTML = parseInt(data[i].price) + " €";
indexImg.setAttribute("src", data[i].imageUrl);
}
This code is going to break if your API returns more than 5 elements. You could try something like cols[i % 5].appendChild(indexCard); or consider other layout strategies.
I want to loop multiple DIV elements.
There are 5 books. I want to loop 5 books in ID: BootLoop.
What I tried?
my_orders.append(data[i].order.bname).appendTo("#bookLoop > div > div > div > h3");
my_orders.append(data[i].order.blink).appendTo("#bookLoop > div > div > div > a");
It didn't work. Where am I making a mistake?
JS:
var my_orders = $("#bookLoop");
$.each(data, function(i, order) {
$("#bookName").append(data[i].order.bname);,
$("#bookURL").append(data[i].order.blink);
});
HTML (Code structure that should be loop):
<div id="bookLoop">
<div class="col-3">
<div class="block-content">
<div class="d-md-flex">
<h3 id="bookName" class="h4 font-w700"></h3>
<div>
<div class="d-md-flex link">
Details
<div>
<div>
<div>
<div>
JSON:
[
{"order":{"id":"61","bname":"Book 1","blink":984}},
{"order":{"id":"42","bname":"Book 2","blink":5414}},
{"order":{"id":"185","bname":"Book 3","blink":4521}},
{"order":{"id":"62","bname":"Book 4","blink":41254}},
{"order":{"id":"15","bname":"Book 5","blink":7464}}
]
I think that what you want is to append each book and link inside #bookLoop, beign each book and link with it's own content.
Below I'm creating elements (nodes) to each book you have then appending it to my_orders.
Take a look if it is what you want, if not, please edit your question showing an example of the desired rendered HTML
var my_orders = $("#bookLoop");
var books = ''
var links = ''
let data = [
{"order":{"id":"61","bname":"Book 1","blink":984}},
{"order":{"id":"42","bname":"Book 2","blink":5414}},
{"order":{"id":"185","bname":"Book 3","blink":4521}},
{"order":{"id":"62","bname":"Book 4","blink":41254}},
{"order":{"id":"15","bname":"Book 5","blink":7464}}
]
$.each(data, function(i, order) {
let col = document.createElement('div')
col.className = 'col-3'
let content = document.createElement('div')
content.className = 'block-content'
let flexC = document.createElement('div')
flexC.className = 'd-md-flex'
let title = document.createElement('h3')
title.className = 'h4 font-w700'
title.textContent = data[i].order.bname;
flexC.append(title)
let flexL = document.createElement('div')
flexL.className = 'd-md-flex link'
let details = document.createElement('a')
details.className = 'bookURL'
details.href = "#"
details.textContent = "Details: " + data[i].order.blink
flexL.append(details)
my_orders.append(col)
col.append(content)
content.append(flexC)
content.append(flexL)
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="bookLoop">
<div>
I want to assign array elements to multiple divs which also have image tag in them using for loop.
Array consists of image paths.
var img_list = ["one.png", "two.png", "three.png", "four.png"];
By using above array I have to create below HTML Structure. All divs should be inside "outer" div with a data-slide attribute which is without ".png".
<div id="outer">
<div class="slide" data-slide="one"><img src="Images/one.png" /></div>
<div class="slide" data-slide="two"><img src="Images/two.png" /></div>
<div class="slide" data-slide="three"><img src="Images/three.png" /></div>
<div class="slide" data-slide="four"><img src="Images/four.png" /></div>
</div>
This is what I wrote:
for (var i=0; i < img_list.length; i++){
var container = document.getElementById("outer").innerHTML;
var new_card = "<div class=\"slide\" data-slide=\'" + img_list[i] + "\'><img src=\'Images/" + img_list[i] + "\' /></div>";
document.getElementById("outer").innerHTML = new_card;
}
But it is only showing the last image.
Please help.
Each time your for loop runs, it is replacing the html element within the "outer" div with the current img html.
In order to have it append you can simply change
document.getElementById("outer").innerHTML = new_card;
to
document.getElementById("outer").innerHTML += new_card; so that the element is appended rather than overwritten.
The code at the question overwrites the .innerHTML within the for loop by setting .innerHTML to new_card at every iteration of the array. You can substitute .insertAdjacentHTML() for setting .innerHTML. Also, substitute const for var to prevent new_card from being defined globally. Include alt attribute at <img> element. You can .split() img_list[0] at dot character ., .shift() the resulting array to get word before . in the string img_list[i] to set data-* attribute value.
const img_list = ["one.png", "two.png", "three.png", "four.png"];
for (let i = 0, container = document.getElementById("outer"); i < img_list.length; i++) {
const src = img_list[i];
const data = src.split(".").shift();
const new_card = `<div class="slide" data-slide="${data}"><img src="Images/${src}" alt="${data}"/></div>`;
container.insertAdjacentHTML("beforeend", new_card);
}
<div id="outer"></div>
You are changing the innerHTML you need to add to it. And use Template literals for creating html strings
var img_list = ["one.png", "two.png", "three.png", "four.png"];
const outer = document.getElementById('outer')
img_list.forEach(img => {
outer.innerHTML += `<div class="slider" data-slide="${img.split('.')[0]}"><img src="Images/${img}" /></div>`
})
console.log(outer.innerHTML)
<div id="outer">
</div>
#Tony7931, please replace the last line of for loop with below code:
document.getElementById("outer").innerHTML += new_card;
You are almost there but, every time you are overriding the slider div.
You just have to add + at assignments section. like below.
document.getElementById("outer").innerHTML += new_card;
Here is the full example:
var img_list = ["one.png", "two.png", "three.png", "four.png"];
for (var i=0; i < img_list.length; i++){
var container = document.getElementById("outer").innerHTML;
var new_card = "<div class=\"slide\" data-slide=\'" + img_list[i].split('.')[0] + "\'><img src=\'Images/" + img_list[i] + "\' /></div>";
document.getElementById("outer").innerHTML += new_card;
}
<div id="outer"></div>
You could also use map method of array and Element.innerHTML to get the required result.
The map() method creates a new array with the results of calling a provided function on every element in the calling array.
Demo
const img_list = ["one.png", "two.png", "three.png", "four.png"];
let result = img_list.map((v, i) => `<div class="slide" data-slide="${v.split(".")[0]}"><img src="Images/${v}"/>${i+1}</div>`).join('');
document.getElementById('outer').innerHTML = result;
<div id="outer"></div>
You can declare your variables outside of the loop and reuse them. This is more efficient.
const and let are preferable to var. You only need to set container once so it can be const. new_card should be let since you need to assign it more than once.
You can also use template string so you don't need all the back slashes.
using forEach will make the code cleaner:
const img_list = ["one.png", "two.png", "three.png", "four.png"];
const container = document.getElementById("outer")
let new_card;
img_list.forEach(i => {
new_card = `<div class=slide data-slide='${i.split(".")[0]}'><img src='Images/${i}'></div>`
container.innerHTML += new_card;
})
<div id="outer">
</div>
Alternately, using reduce:
const img_list = ["one.png", "two.png", "three.png", "four.png"];
const container = document.getElementById("outer")
const reducer = (a, i) => a + `<div class=slide data-slide='${i.split(".")[0]}'><img src='Images/${i}'></div>`
container.innerHTML = img_list.reduce(reducer, '')
<div id="outer">
</div>
So I am attempting to display all the questions and responses from my Firebase database. It is showing up fine, but it looks ugly, because there is no space between the question and responses. I've tried using the createElement feature as well as .innerHTML to add a nonbreaking space. Nothing is working. Here is the code I have thus far: Thanks for your help!
<button id="all" onclick="button()"> View All </button>
<h4> All Users: </h4>
<script>
function button(){
var userRef = new Firebase("https://speedpoll-1fd08.firebaseio.com");
userRef.on("value", function(snapshot) {
// The callback function will get called twice, once for "fred" and once for "barney"
snapshot.forEach(function(childSnapshot) {
// key will be "fred" the first time and "barney" the second time
var key = console.log(childSnapshot.key());
// childData will be the actual contents of the child
// var userInfo = console.log(childSnapshot.val());
var element = document.getElementById("viewAll");
var para = document.createElement("h5");
var node = document.createTextNode("Question: " + childSnapshot.key());
console.log(childSnapshot.child("Option1").child('Response1').val());
var node1= document.createTextNode("Response 1: " + childSnapshot.child("Option1").child('Response1').val());
//var space = document.createElement(" ");
element.innerHTML += " ";
var node2= document.createTextNode("Response 2: " + childSnapshot.child('Option2').child('Response2').val());
var node3= document.createTextNode("Response 3: " + childSnapshot.child('Option3').child('Response3').val());
para.appendChild(node);
//para.appendChild(space);
para.appendChild(node1);
para.appendChild(node2);
para.appendChild(node3);
element.appendChild(para);
});
});
}
</script>
<div id="viewAll">
</div>
You can add a line by adding an <hr> element, as explained here: http://www.htmlgoodies.com/tutorials/getting_started/article.php/3479441
Like this one:
You can also add <div> sections for each element, and style the margins, paddings and borders with CSS. The same for <p> sections.
You can play around with this JSFiddle:
http://jsfiddle.net/jmgomez/n0e1ev8e/
Check this out also on how to style borders with CSS: http://www.w3schools.com/css/css_border.asp