Render each Objects in an array in HTML from JavaScript - javascript

I have a JavaScript array of objects taken from a JSON file. Each object in the array represents a product. The following code shows the JavaScript. The console.log displays each element in the console, however the innerHTML only renders the last as this is the last value to be rendered.
/* global $ */
var output = document.getElementById('output');
var products = [];
$.getJSON('/products', function(data){
output.innerHTML = data
for(var keys in data){
console.log(data[keys]);
products.push(data[keys]);
output.innerHTML = data[keys].NAME;
}
// output.innerHTML = products;
//console.log(products)
});
I want each product to be rendered in it's own output div. How would I display each element in the HTML instead of just the last?

Just append the element to your output. Actually you did it.
Change this:
output.innerHTML = data[keys].NAME;
To this:
$('#output').append(`<div>${data[keys].NAME}</div>`);
So:
for(var keys in data){
console.log(data[keys]);
products.push(data[keys]);
$('#output').append(`<div>${data[keys].NAME}</div>`);
}
I would recommend you also to change the for...in with a simple forEach, so to change the loop into this:
data.forEach((el) => {
products.push(el);
$('#output').append(`<div>${el.NAME}</div>`);
});
The error in your code was just that you were overriding the HTML content of your element every time. If you change:
output.innerHTML = data[keys].NAME;
to this:
output.innerHTML += data[keys].NAME;
It should already work

You can use jQuery "append". You dont need to make product object.
Try like this:
for(var keys in data){
$(".productList").append( "<div>"+data[keys].NAME+"</div>" );
}

Basically, your output element should be a wrapper containing other elements repeated for each product. One semantic option is to use a list, such as ul + li.
You should iterate your products and append its piece of HTML to an array. When you are done processing them, you assign that chunk of HTML to the output element.
// Just to keep your code untouched:
const $ = {
getJSON(url, callback) {
callback([{
ID: 1,
NAME: 'Product 1',
PRICE: '2.50',
}, {
ID: 2,
NAME: 'Product 2',
PRICE: '1.25',
}, {
ID: 3,
NAME: 'Product 3',
PRICE: '10.00',
}]);
},
};
const output = document.getElementById('output');
let productsArray = [];
$.getJSON('/products', function(products){
productsArray = products;
output.innerHTML = products.map(product => {
return `<li data-id="${ product.ID }">
<span>${ product.NAME }</span>
<span>${ product.PRICE }</span>
</li>`;
}).join('');
});
<ul id="output"></ul>

$('#output').append(`<div>${data[keys].NAME}</div>`);

In reference to #VK321, you can also use the .map method.
data.map(element => {
$(".productList").append( `<div>${element.NAME}</div>` );
})

Related

Adding inline tags within text node in javascript

Hi there this might be easy but I am new and just learning I need help with 2 problems.
First, when creating element using document.createElement() how to add class or id to that element?
---- found a solution for this problem of className = "" or id="" by adding a variable to differentiate the data originated from the array which I added and named id ----
Second, using createTextNode() to avoid using the innerHTML how to add the line breaker tag within?
Lets say I have an array of items = [{id: "item-1", name: "apple", price:1} , {id:"item-2" ,name : "mango", price:3}];
and I want to go through them with:
let data = document.getElementById("items-data");
items.forEach(item => {
let container = document.createElement("div"), //here i want to add a defined id for further use
itemData = document.createTextNode(
`item name : ${item.name} price: ${item.price}`); //here i want to add the br
container.appendChild(itemData);
container.id = item.id;
data.appendChild(container);
};
Do you mean something like this:
container.appendChild(document.createElement("br"));
let base = document.querySelector(".base");
let items = [{
id: "item-1",
name: "apple",
price: 1
}, {
id: "item-2",
name: "mango",
price: 3
}];
items.forEach(item => {
let container = document.createElement("div"), //here i want to add a defined id for further use
itemData = document.createTextNode(
`item name : ${item.name} price: ${item.price}`); //here i want to add the br
container.appendChild(itemData);
container.appendChild(document.createElement("br")); // <-- Add the line break to the node element
container.id = item.id;
base.appendChild(container);
});
<div class="base"></div>

Dynamically created list items draggable JavaScript

I am dynamically populating a list of senators, separated by political affiliation. That part works. I need to make each list item draggable. I can't get that to work.
I tried this:
document.getElementById(name).setAttribute('draggable');
in my list population loop, but I really don't know if that's the right way.
senatorList.forEach(({name, party}) => {
let itemEl = document.createElement('li');
itemEl.textContent = name;
let listId = party === 'Democrat' ? '#democrats' : '#republicans';
let listEl = document.querySelector(listId);
document.getElementById(name).setAttribute('draggable');
listEl.appendChild(itemEl);
});
Your code contains a couple of errors:
setAttribute requires two arguments: attribute and value.
You called document.getElementById(name) before adding itemEl to the document.
If I understood your intentions correctly, the code should look similar to this:
const senatorList = [{
name: 'senator1',
party: 'Democrat'
},
{
name: 'senator2',
party: 'Democrat'
},
{
name: 'senator3',
party: 'Republican'
},
];
senatorList.forEach(({
name,
party
}) => {
let itemEl = document.createElement('li');
itemEl.textContent = name;
let listId = party === 'Democrat' ? '#democrats' : '#republicans';
let listEl = document.querySelector(listId);
itemEl.setAttribute('draggable', 'true');
listEl.appendChild(itemEl);
});
<div id="democrats"></div>
<div id="republicans"></div>

Display pictures based on specific student ID

So after pulling all the information from my sql tables, I put them into 2 variables called response1 and response2.Shown below are what's currently inside the arrays. My goal is to display the pictures, beside each student. If a picture doesn't exsist, it can just be blank for now. So i've gotten the picture from DB to display by using base64 encode, but i'm only currently doing it for the id:20000001, since i'm not sure how to do it for other ones.
I had an idea to maybe replace
student_image= findItemByID(response2,'20000001');
with
student_image= findItemByID(response2,element.id); ?
but not sure if this is correct logic?
Inside my Object.keys final loop, how should I fix html+='<img src="data:image/jpeg;base64,'+student_image.photo+'">' so that it adds the image of the specific id?
Response1 array of object:
0: {Class_Student_Group: 1, names: "Lastname1, Firstname1", id: 20000001}
1: {Class_Student_Group: 2, names: "Lastname2, Firstname2", id: 20000002}
2: {Class_Student_Group: 3, names: "Lastname3, Firstname3", id: 20000003}
3: {Class_Student_Group: 5, names: "Lastname4, Firstname4", id: 20000004}
4: {Class_Student_Group: 3, names: "Lastname5, Firstname5", id: 20000005}
Response2 array of objects:
0: {student_id: "20000001", photo: ""}
1: {student_id: "20000001", photo: "/9j/4AAQSkZJRgABAQAAAQABAAD/4QB6RXhpZgAASUkqAAgAAA…9a1EtFKAnd09f/rVlwfdFbVw7LPIoOAGNYwjc/SIaxR//2Q=="}
2: {student_id: "20000002", photo: ""}
3: {student_id: "20000003", photo: ""}
final:
1: Array(4)
0: {Class_Student_Group: 1, names: "Lastname1, Firstname1", id: 20000001}
1: {Class_Student_Group: 1, names: "Lastname9, Firstname9", id: 20000009}
2: {Class_Student_Group: 1, names: "Lastname15, Firstname15", id: 20000015}
3: {Class_Student_Group: 1, names: "Lastname19, Firstname19", id: 20000019}
length: 4
__proto__: Array(0)
2: (4) [{…}, {…}, {…}, {…}]
3: (4) [{…}, {…}, {…}, {…}]
output so far:
<script type="text/javascript">
$(document).ready(function() {
var response= <?php echo json_encode($table); ?>;
var response2= <?php echo json_encode($result); ?>;
function findItemByID(arr, id) {
return arr.find((photoObj) => {
return photoObj.photo.trim().length !== 0 && photoObj.student_id === id
})
}
var final = {}
response.forEach(function(element) {
final[element.Class_Student_Group] = final[element.Class_Student_Group] || [];
final[element.Class_Student_Group].push(element);
});
let student_image =''
Object.keys(final).forEach(function(Group) {
let html = '';
//add the table opening tag to the html variable
html += '<table>';
//Append the 'category' header
html += '<tr>';
html += '<td><h1>'+"Group"+ Group+'</h1></td>';
html += '</tr>';
// Loop through the results for this 'category'
student_image= findItemByID(response2,'20000001');
final[Group].forEach(function(element) {
var randomImage = images[Math.floor(Math.random() * images.length)];
var names = element.names;
var id=element.id;
var img = "<img src=' " + randomImage+ " ' />";
html += '<tr>';
html += '<td><p>' + names + '</p></td> ';
html += '<td><p>' + id + '</p></td> ';
html+='<img src="data:image/jpeg;base64,'+student_image.photo+'">'
html += '</tr>';
});
//add the table closing tag to the html variable
html += '</table>';
$('#tables_container').append(html);
});
});
</script>
OK. Quite a few things going on here.
Basically the reason(s) the findItemByID() function wasn't working was because A. (and I have to assume you knew this) you were passing in the same ID every time it was called, B. by putting it before you called final[Group].forEach(function(element) you couldn't pass in the right value for the id, as the id is a property of that element variable, and C. === is a strict equality operator, which means it only returns true if the values are the same and they are the same type. In one array of objects that value is a string and in the other it's a number.
You are doing a lot of things out of order. Take a step back and try to think about what this code is intended to do and write it one step at a time, and break your steps into functions whenever practical like I have done here. Look over the changes I have made to your code, and the comments I added. Generally when writing code you want to use functions to make things more readable, and break them apart so you are dealing with the least amount of complexity as possible at any given time. A table works like table - > row - > column -- write your code that way.
I don't know anything about using Base64 for images in HTML, but a look at this link suggests that the data you have supplied here won't work. Check out the decoder in the accepted answer.
I changed the way you were iterating over your final object. This is probably mostly a matter of taste, but to me it's more readable. You can learn more about it here
Use better names! It's so much easier when you're trying to figure out why something is broken if you aren't also trying to remember what data is in response vs response2. Just call them studentDataArray and imageDataArray or something.
$(document).ready(function () {
loadTable();
});
let array1 = [
{ Class_Student_Group: 1, names: "Lastname1, Firstname1", id: 20000001 }
, { Class_Student_Group: 2, names: "Lastname2, Firstname2", id: 20000002 }
, { Class_Student_Group: 3, names: "Lastname3, Firstname3", id: 20000003 }
, { Class_Student_Group: 5, names: "Lastname4, Firstname4", id: 20000004 }
, { Class_Student_Group: 3, names: "Lastname5, Firstname5", id: 20000005 }
]
let array2 = [{ student_id: "20000001", photo: "" }
, { student_id: "20000001", photo: "/9j/4AAQSkZJRgABAQAAAQABAAD/4QB6RXhpZgAASUkqAAgAAA…9a1EtFKAnd09f/rVlwfdFbVw7LPIoOAGNYwjc/SIaxR//2Q==" }
, { student_id: "20000002", photo: "" }
, { student_id: "20000003", photo: "" }];
function findItemByID(arr, id) {
return arr.find((photoObj) => {
return photoObj.photo.trim().length !== 0 && photoObj.student_id == id // because the id property in the student object is a number and in the photo array it's a string, change this to '==', which evaluates '2' as equal to 2. === only returns true if they are the same type
//also you have been checking for a student_id property here, which doesn't exist on the second array's objects, so this wasn't returning anything
})
}
function getFinalObject(response) {
var final = {}
response.forEach(function (element) {
final[element.Class_Student_Group] = final[element.Class_Student_Group] || [];
final[element.Class_Student_Group].push(element);
});
return final;
}
function appendHtmlToDoc(final, response2, images) {
let html = '';
//add the table opening tag to the html variable
html += '<table>';
for (let Group in final) { //this will loop through final's properties, in this case, the 'groups'
if (final.hasOwnProperty(Group)) { //use hasOwnProperty to make sure you aren't looping through irrevelant properties (https://stackoverflow.com/questions/8312459/iterate-through-object-properties)
//Append the 'category' header
html += '<tr>';
html += '<td><h1>' + "Group" + Group + '</h1></td>';
html += '</tr>';
// Loop through the results for this 'category'
final[Group].forEach(function (element) { //you already have the Group array in the Group variable
let student_image = findItemByID(response2, element.id); //search for the image data using this element's id property
// var randomImage = images[Math.floor(Math.random() * images.length)]; //should pass 'images' into this function, but I don't know where it came from and randomImage/img isn't used in the code you provided, so I removed it
var names = element.names;
var id = element.id;
// var img = "<img src=' " + randomImage + " ' />";
html += '<tr>';
html += '<td><p>' + names + '</p></td> ';
html += '<td><p>' + id + '</p>';
if (student_image) { //check if something was returned when you searched for the photo, otherwise you'll have a blank image here
html += '<td><img src="data:image/jpeg;base64, ' + student_image.photo + '"></td>'; //I don't know anything about using images in HTML with base64, but a look at this link (https://stackoverflow.com/questions/8499633/how-to-display-base64-images-in-html) suggests that what you have provided won't work
}
//I also added a td around your img tag
html += '</tr>';
});
}
}
//add the table closing tag to the html variable
html += '</table>';
//console.log(html)
$('#tables_container').append(html);
}
function loadTable() {
//move your php script calls here
let finalObj = getFinalObject(array1);
appendHtmlToDoc(finalObj, array2);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="tables_container"></div>
Try:
if(!photo.id) {
// There's no image
} else {
// There's an image
}

Compare 'order' to 'products' array and print product names if in the order?

I have an array of products:
const products = {
{
id: item1,
name: 'My product',
price: 100
},
{
id: item2,
name: 'My other product',
price: 200
},
{
id: item3,
name: 'My other other product',
price: 150
}
}
I also have an order state which says which and how many products are in the order. In this instance there is 1 item1 and 2 item2 in the order:
const orderState = {
item1: 1,
item2: 2
}
How can I render the prodcut name and number of times its in the order? Im using React but I think vanilla JS is all thats needed for the solution.
My HTML output needs to be something like:
<ul>
<li>My product x1 = $1</li>
<li>My other product x2 = $4</li>
</ul>
The way you're storing your data is what seems to be giving you difficulty. First, make the array of products an actual array:
const products = [
{
id: item1,
name: 'My product',
price: 100
}, //...
];
Additionally, what is that item1 value? Is that an actual ID of some kind, like an integer? That's what you'll use to identify the products later.
Then for your "order state", create an object which holds an array of references to the products. Something like this:
const orderState = {
products: [
{
productID: item1,
quantity: 1
},
{
productID: item2,
quantity: 2
}
]
}
Now that you have a more sensible data structure, you can more easily operate on that structure. There are a variety of ways to build your output, and how you do it may depend heavily on what other tools you're using (such as template engines and such). But just to demonstrate the logic, let's build a simple string:
var output = '<ul>';
for (var i = 0; i < orderState.products.length; i++) {
var product = {};
for (var j = 0; j < products.length; j++) {
if (products[j].id == orderState.products[i].id) {
product = products[j];
break;
}
}
output += '<li>' + product.name + ' x' + orderState.products[i].quantity + ' = $' + (product.price * orderState.products[i].quantity) + '</li>';
}
output += '</ul>';
From this you can refactor and improve as needed. For example, the logic to find the product based on its id can be extracted into its own function, or perhaps even reduced to a one-liner using built-in JavaScript functionality or framework functionality. (underscore.js is good for functionality like that.)
But the basic idea is to keep the data structures sensibly organized. Then the code which operates on those structures becomes trivial.
With below solution you can get the names of selected products as per your question statement.
let productsOrderedIds = Object.keys(orderState);
let proNames = [];
for(let pro of products) {
if(productsOrderedIds.indexOf(pro.id) !== -1){
proNames.push(pro.name);
}
}
console.log(proNames);

How to get JSON Data depending on other data values in JavaScript

My Json is like this:
[
{"isoCode":"BW","name":"Botswana ","CashOut":"Y","BankOut":"","MMT":null},
{"isoCode":"BR","name":"Brazil ","CashOut":"Y","BankOut":"Y","MMT":null},
{"isoCode":"BG","name":"Bulgaria ","CashOut":"Y","BankOut":"Y","MMT":"Y"},
{"isoCode":"BF","name":"Burkina Faso","CashOut":"Y","BankOut":"","MMT":null},
{"isoCode":"BI","name":"Burundi","CashOut":"","BankOut":"","MMT":"Y"},
{"isoCode":"KH","name":"Cambodia","CashOut":"Y","BankOut":"","MMT":null}
]
I want all the names which have BankOut value as "Y" into an array using JavaScript, in order to use those names in my protractor automation.
You need to use filter method of array. It takes function as it argument. And runs it against each element of array. If function returns true (or other truthy value) then that element stays in newly created array.
var list =[ {"isoCode":"BW","name":"Botswana ","CashOut":"Y","BankOut":"","MMT":null},
{"isoCode":"BR","name":"Brazil ","CashOut":"Y","BankOut":"Y","MMT":null},
{"isoCode":"BG","name":"Bulgaria ","CashOut":"Y","BankOut":"Y","MMT":"Y"},
{"isoCode":"BF","name":"Burkina Faso ", "CashOut":"Y","BankOut":"","MMT":null},
{"isoCode":"BI","name":"Burundi","CashOut":"","BankOut":"","MMT":"Y"},
{"isoCode":"KH","name":"Cambodia","CashOut":"Y","BankOut":"","MMT":null}
];
var onlyBankOutY = list.filter(function (item) {
return item.BankOut === 'Y';
});
document.body.innerHTML = onlyBankOutY.map(function (item) {
return JSON.stringify(item);
}).join('<br>');
var list =[
{"isoCode":"BW","name":"Botswana ","CashOut":"Y","BankOut":"","MMT":null},
{"isoCode":"BR","name":"Brazil ","CashOut":"Y","BankOut":"Y","MMT":null},
{"isoCode":"BG","name":"Bulgaria ","CashOut":"Y","BankOut":"Y","MMT":"Y"},
{"isoCode":"BF","name":"Burkina Faso ", "CashOut":"Y","BankOut":"","MMT":null}, {"isoCode":"BI","name":"Burundi","CashOut":"","BankOut":"","MMT":"Y"},
{"isoCode":"KH","name":"Cambodia","CashOut":"Y","BankOut":"","MMT":null}
];
var names = [];
list.forEach(function(el) {
if (el.BankOut === 'Y') {
names.push(el.name)
}
})

Categories

Resources