How to fix Javascript associative array error - javascript

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!

Related

How to make multiple image source assignments not make the page stuck?

I need to dynamically create a list of a couple thousand elements. Each list item contains an image of about half a Kb and some text.
The problem is that the assignment of all image sources to my list items, using the .src of my <img> elements, is taking a long time and making the page completely stuck for some seconds.
Is there a way that I could do this maybe asynchronously or more efficiently so that the page doesn't get stuck during the list generation?
Here's a simplified version of my code. If I remove the line with .src assignment, the code runs instantaneously.
// About a couple thousand elements
const item_data = [
{text: "text1", image: "img/image1.png"},
{text: "text2", image: "img/image2.png"},
... ];
const my_list = document.createElement("ul");
for (const item of item_data) {
const list_item = document.createElement("li");
const list_item_text = document.createElement("p");
list_item_text.innerText = item.text;
const list_item_image = document.createElement("img");
list_item_image.src = item.image;
list_item.appendChild(list_item_text);
list_item.appendChild(list_item_image);
my_list.appendChild(list_item);
}
document.body.appendChild(my_list);

I'm making a level maker with a preview from the code generated by the level maker, how could I do this?

I have made a Level Generator. Basically there is a 3 by 20 grid of squares, and you can select either one and depending on what you select when you click the button to generate it generate some code for you into a variable (string). It works perfectly but how am I going about to then get that generated code and turn it into a preview.
So far I found out using the keyword eval() but this only does the last line? Any ideas?
Here is a picture of what the layout is:
The Website So Far
The code that I originally had to detect the code was:
if (container.childNodes[index].innerText == 'pos3') {
if (container.childNodes[index].id == '1 second') {
text = text + '\n' + 'cube1 = new theCubeCreator(pos3, 0, 2, 1000),'
//amtselected = amtselected + 1
}....
Something like that then I would bundle it all up with this
var pos1 = 125 //middle
var pos2 = 70 //left
var pos3 = 180 //right
text = text + '\n' + 'cube1 = new theCubeCreator(pos2, 0, 2, 1000)' // Must add this to make it a end
var evaluation = eval(text)
console.log(evaluation);
Sorry if this is hard to read or if you want me to send examples.
What you are doing is bad practice. You should make an object that holds the functions and a generator function that converts and object into a function.
// object for the function / class you want to run
var data = {
name: "console.log",
isClass: false,
params: ["pos2", 0, 2, 1000],
};
var domParse = {
name: "DOMParser",
isClass: true,
params: ["<div>Hello World</div>", "text/html"],
};
var funcs = {
DOMParser: (args) => {
const dom = new DOMParser();
return dom.parseFromString(...args);
},
"console.log": (args) => console.log(...args),
};
// function to generate a function from the object.
function generate({ name, isClass, params }) {
return funcs[name](params);
}
generate(data); // console.log's pos2 0 2 1000
generate(domParse); // creates a DOM object
I took another way than doing eval() (well i still used eval). What I was doing was, to have a variable let text = '' then adding onto that variable doing something like this text = text + \n + '...'
Already this is bad so i took a different approach. all i changed was instead of having a string variable i would have a Array to store my code. Declearing it like this let text = [] then using push() to add the code to it, like so text.push(eval(...)).
Thats what i did to complete to fix my problem if you have any other way or eisier to follow (and yes i know this is messy) then comment (:

Get all data from api and insert into HTML

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!

Using for loop to write a paragraph inside .docx file using js with npm docx

the main issue: i want to insert more than 40 text to the Microsoft word document.
through java script code :
// requiring modules
const fs = require('fs'),
docx = require('docx');
// create a new doc
const doc = new docx.Document();
// get paragraph text
const getData = new docx.Paragraph({
children:[
new docx.TextRun({
text: 'Welcome from getData',
size: 72
}),
],
})
//add a section to document to render the paragraph
doc.addSection({
children:[
getData
]
});
//write the buffer to the file.docx
docx.Packer.toBuffer(doc).then((Buffer)=>{
fs.writeFileSync("text.docx" , Buffer);
})
i tried every thing but nothing work with me.
I'd the same issue... But here is a work around. The Docx.J's library doesn't allow loop in either TableCell or TableRow, so it's best you loop outside Table(). Assuming you have a list of string...
let myStrings = ['firstString', 'secondString', 'thirdString'];
const buildParagraph = async(arr)=>{
let paragraphArray = []
arr.map((cur , index)=> {
paragraphArray.push(new Paragraph(cur))
});
return paragraphArray;
};
So buildParagrahp() will give you an array of paragraphs like you intended and you can just place it as the value of the children in your Table(), this should also apply to other things you may try looping...

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

Categories

Resources