How to populate multiple JavaScript arrays of objects to HTMLDOM - javascript

I am having difficulty to get all the array of objects and display it into HTML lists. Can anyone help me, please. The below is my HTML and JavaScript code. Looking forward to your help.
const allData = [{
date: '2nd',
venue: 'venue1',
location: 'location1',
},
{
date: '3rd',
venue: 'venue2',
location: 'location2',
},
{
date: '4th',
venue: 'venue3',
location: 'location3',
}
]
allData.forEach(data => {
[...document.querySelectorAll('.targets')].forEach(list => {
list.innerHTML = `
<h5 >DATE</h5>
<h4 >${data.date}</h4>
<h5 >VENUE</h5>
<h4 >${data.venue}</h4>
<h5 >LOCATION</h5>
<h4 >${data.location}</h4>
<Button >BUY TICKETS</Button>
`;
})
});
<ul>
<li class="targets"></li>
</ul>

If you change the order of for loops execution and append each string to the previous it works!
const allData = [{
date: '2nd',
venue: 'venue1',
location: 'location1',
},
{
date: '3rd',
venue: 'venue2',
location: 'location2',
},
{
date: '4th',
venue: 'venue3',
location: 'location3',
},
];
const list = document.querySelector('.target')
let innerHTML = '';
allData.forEach(data => {
innerHTML += `
<li>
<h5 class = "shows__date">DATE</h5>
<h4 class = "shows__calander">${data.date}</h4>
<h5 class = "shows__venue-title">VENUE</h5>
<h4 class = "shows__venue">${data.venue}</h4>
<h5 class = "shows__location-title">LOCATION</h5>
<h4 class = "shows__location">${data.location}</h4>
<Button Class = "shows__btn">BUY TICKETS</Button>
</li>
`;
});
list.innerHTML = innerHTML;
<ul class="target">
</ul>

I think you don't need to loop for class='targets' because you only have one li in your html code. It might be better to just get the ul element and then loop allData variable, then change the ul innerHTML on each loop.
HTML Code
<ul></ul>
JS Code:
const allData= [
{
date: '2nd',
venue: 'venue1',
location: 'location1',
},
{
date: '3rd',
venue: 'venue2',
location: 'location2',
},
{
date: '4th',
venue: 'venue3',
location: 'location3',
},
]
let ul = document.querySelector('ul')
let listContent = ''
allData.forEach(data=>{
listContent = listContent +
`
<li>
<h5 >DATE</h5>
<h4 >${data.date}</h4>
<h5 >VENUE</h5>
<h4 >${data.venue}</h4>
<h5 >LOCATION</h5>
<h4 >${data.location}</h4>
<Button >BUY TICKETS</Button>
</li>
`;
});
ul.innerHTML = listContent
Edited based on pilchard comment

The OP provides a basic list structure by the "naked" <ul/> / <li/>
markup.
Thus, there is only a sole <li class="targets"></li> element which can be accessed with a query like '.targets'. Which means, the OP always writes to one and the same element which shows the expected result of a list which features just one element with the data-array's last item-data.
But the <li/> element can be used as a blueprint for creating other list-item elements via <node>.cloneNode which all will be <li class="targets"></li>-alike.
Now one can assign the correct data-item related html content to each newly created list-item clone which also gets appended to its parent list-element ...
const allData = [{
date: '2nd',
venue: 'venue1',
location: 'location1',
}, {
date: '3rd',
venue: 'venue2',
location: 'location2',
}, {
date: '4th',
venue: 'venue3',
location: 'location3',
}];
const venueItemBlueprint = document.querySelector('li.targets');
const venueList = venueItemBlueprint && venueItemBlueprint.parentElement;
if (venueList) {
venueList.innerHTML = '';
allData.forEach(venueData => {
const venueItem = venueItemBlueprint.cloneNode();
venueItem.innerHTML = `
<h5>DATE</h5>
<h4>${ venueData.date }</h4>
<h5>VENUE</h5>
<h4>${ venueData.venue }</h4>
<h5>LOCATION</h5>
<h4>${ venueData.location }</h4>
<Button>BUY TICKETS</Button>`;
venueList.appendChild(venueItem);
});
}
<ul>
<li class="targets"></li>
</ul>

Related

KnockoutJS - How to hide certain elements inside foreach using Observable Arrays?

I have a list of WebsiteOwners. I'm trying to build a UI which will display more information about the owners when I click on them.
this.toExpand = ko.observableArray(); //initialize an observable array
this.invertExpand = ko.observable("");
this.invertExpand = function (index) {
if (self.invertExpand[index] == false) {
self.invertExpand[index] = true;
alert(self.invertExpand[index]); //testing whether the value changed
}
else {
self.invertExpand[index] = false;
alert(self.invertExpand[index]); //testing whether the value changed
}
};
Here's the HTML code :
<div data-bind="foreach: WebsiteOwners">
<div>
<button data-bind="click: $root.invertExpand.bind(this,$index())" class="label label-default">>Click to Expand</button>
</div>
<div data-bind="visible: $root.toExpand()[$index]">
Primary Owner: <span data-bind="text:primaryOwner"></span>
Website Name : <span data-bind="text:websiteName"></span>
//...additional information
</div>
</div>
You can store one of your WebsiteOwner items directly in your observable. No need to use an index.
Don't forget you read an observable by calling it without arguments (e.g. self.invertExpand()) and you write to it by calling with a value (e.g. self.invertExpand(true))
I've included 3 examples in this answer:
One that allows only a single detail to be opened using knockout
One that allows all details to be opened and closed independently using knockout
One that does not use knockout but uses plain HTML instead 🙂
1. Accordion
Here's an example for a list that supports a single expanded element:
const websiteOwners = [
{ name: "Jane", role: "Admin" },
{ name: "Sarah", role: "Employee" },
{ name: "Hank", role: "Employee" }
];
const selectedOwner = ko.observable(null);
const isSelected = owner => selectedOwner() === owner;
const toggleSelect = owner => {
selectedOwner(
isSelected(owner) ? null : owner
);
}
ko.applyBindings({ websiteOwners, isSelected, toggleSelect });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<ul data-bind="foreach: { data: websiteOwners, as: 'owner' }">
<li>
<span data-bind="text: name"></span>
<button data-bind="
click: toggleSelect,
text: isSelected(owner) ? 'collapse' : 'expand'"></button>
<div data-bind="
visible: isSelected(owner),
text: role"></div>
</li>
</ul>
2. Independent
If you want each of them to be able to expand/collapse independently, I suggest adding that state to an owner viewmodel:
const websiteOwners = [
{ name: "Jane", role: "Admin" },
{ name: "Sarah", role: "Employee" },
{ name: "Hank", role: "Employee" }
];
const OwnerVM = owner => ({
...owner,
isSelected: ko.observable(null),
toggleSelect: self => self.isSelected(!self.isSelected())
});
ko.applyBindings({ websiteOwners: websiteOwners.map(OwnerVM) });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<ul data-bind="foreach: websiteOwners">
<li>
<span data-bind="text: name"></span>
<button data-bind="
click: toggleSelect,
text: isSelected() ? 'collapse' : 'expand'"></button>
<div data-bind="
visible: isSelected,
text: role"></div>
</li>
</ul>
3. Using <details>
This one leverages the power of the <details> element. It's probably more accessible and by far easier to implement!
const websiteOwners = [
{ name: "Jane", role: "Admin" },
{ name: "Sarah", role: "Employee" },
{ name: "Hank", role: "Employee" }
];
ko.applyBindings({ websiteOwners });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<ul data-bind="foreach: websiteOwners">
<li>
<details>
<summary data-bind="text: name"></summary>
<div data-bind="text: role"></div>
</details>
</li>
</ul>

What method to use to access multiple objects in an array?

I'm new to javascript and still learning them.
So I was building a project where I want to display a multiple object, which I put it in an array, to the DOM.
I am not sure what method to use to access the object inside the array.
<div class="container">
<div class="hero">
<h2>List of Names</h2>
</div>
<ul class="name-list"></ul>
</div>
This is my js file:
const nameList = document.querySelector('.name-list');
//List of Names
const john = {
name: 'john',
car: 'fiat',
address: 'new york'
}
const mike = {
name: 'mike',
car: 'toyota',
address: 'sydney'
}
const greg = {
name: 'greg',
car: 'nissan',
address: 'melbourne'
}
//Store list of names in an array
const allNames = [
john,
mike,
greg
]
function displayName (){
//Not sure what methods to use to
return `
<li>
<p>Name: ${allNames.name}</p>
<p>Car: ${allNames.car}</p>
<p>Address: ${allNames.address}</p>
</li>
`
}
So I kind of want to display all the objects in the DOM.
Is it necessary to put the objects in the array first? What methods do I use to return a list in the file? Or do you know any easier methods to display all the objects in the DOM?
Thank you so much for the help.
Maybe you can try something like this :
function showNameList() {
const allNames = [
{
name: 'john',
car: 'fiat',
address: 'new york'
},
{
name: 'mike',
car: 'toyota',
address: 'sydney'
},
{
name: 'greg',
car: 'nissan',
address: 'melbourne'
}
]
var namelist = allNames.map(function (t, i) {
return `<b>Name : </b> ${t.name}<br/><b>Car : </b> ${t.car}<br/><b>Address : </b> ${t.address}<br/><br/>`;
})
document.getElementById('name-list').innerHTML =
'<li>' + namelist.join('</li><li>') + '</li>'
}
showNameList()
<div class="container">
<div class="hero">
<h2>List of Names</h2>
</div>
<ul id="name-list"></ul>
</div>
use map function to display them :
const values = allNames.map(item=>{
return(
<li>
<p>Name: ${item.name}</p>
<p>Car: ${item.car}</p>
<p>Address: ${item.address}</p>
</li>
)
})
<div class="container">
<div class="hero">
<h2>List of Names</h2>
</div>
<ul class="name-list">
{values}
</ul>
</div>

setting single element to hidden in vue js when mapped

kinda new to vue, I have mapped out some data from my initial data object in vue.js I am trying to hide and show only the items within that iteration of the mapping when the user selects the heading. I am using the isHidden prop in vue to hide and show my list items but when selecting any heading it shows all the tags instead of those associated with that specific header.
anyone know the proper way to do this? should I use some index or id from e.target? or should I give each list item a 'hidden' property and change it that way somehow?
here's my list that I mapped out
<div v-for="item in list">
<h4 v-on:click="viewItemsinCat()">{{item.category}}</h4>
<ul>
<li v-if="!isHidden" v-for="item in item.food">
{{item}}
</li>
</ul>
</div>
then I have my data like so:
data: {
list: [{
category: 'Baked goods',
food: ['bread', 'cookie', 'butter', 'powder']
}, {
category: 'meats',
food: ['chicken', 'turkey', 'beef']
}, {
category: 'fruits',
food: ['bannana', 'apple', 'pineapple']
}, {
category: 'canned goods',
food: ['tomatoes', 'green beans', 'corn']
}, {
category: 'veggies',
food: ['broccoli', 'celery', 'lettuce']
}, {
category: 'pantry',
food: ['broom', 'mop', 'dried beans']
}, ],
isHidden: true,
}
then I have my method to alter isHidden
viewItemsinCat: function(){
this.isHidden = false
},
Add a selected property to contain the currently selected item when the user clicks:
data() {
return {
selected: null,
list: [...]
}
}
<div v-for="item in list">
<h4 v-on:click="selected=item.category">{{item.category}}</h4>
<ul v-if="selected==item.category">
<li v-for="food in item.food">
{{ food }}
</li>
</ul>
</div>
Here's a demo

Javascript ES6 array loop that populates code only when on certain pages

i'm in school currently learning how to program using javascript (forgive me if my terminology is bad. feel free to correct me.) Myself and a team of four are creating a site. the requirements are that we must have 4 pages and each page needs to have a loop of some kind, we must use bootstrap, and we can only use one js file for all the pages. We are using a printToDom function to populate bootstrap cards on separate pages, and for some reason i can't get mine to work. i'm wondering if this has something to do with how our code is set up, specifically the for loops we're using. is there a way that i can incorporate an if statement that makes it to where our printToDom will print certain pieces of the for loop when on different pages? If so is there a term for it or something i can look up to get more insight?
EDIT: I probably should have said this in my original post, but I'm considering merging the two for loops that are seen in my code below because currently i have 2 separate for loops, but only one gets populated when on the tours page, the other one is supposed to populate some recent events from the array recentEvents but it doesn't. I tested it in JS fiddle and the code works there so i'm just wondering why it won't work when in the js file along side the rest of the code and I'm not sure how to phrase what i'm looking for.
javascript below for more context
const tourStops=[
{ location: "Denver, Colorado ",
venue: " Pepsi Center ",
date: "MON 04/20/2020",
id: 1
},
{
location: "Las Vegas, Nevada",
venue: " Flamingo Hotel",
date: "FRI 04/24/2020",
id: 2
},
{
location: "Hollywood, California",
venue: " Troubadour ",
date: "SAT 05/02/2020",
id: 3
},
{
location: "Portland,Oregon",
venue: " Moda Center ",
date: "FRI 05/15/2020",
id: 4
},
{
location: "Washington, D.C. ",
venue: " Capital One Arena",
date: "FRI 05/22/2020",
id: 5
},
{
location: "Bangor, Maine ",
venue: " Darlings Waterfront",
date: "FRI 06/05/2020",
id: 6
},
{
location: "Boston, Massachusetts",
venue: " Wilbur Theater ",
date: "SAT 06/20/2020",
id: 7
},
{
location: "Anchorage, Alaska ",
venue: "Atwood Concert Hall",
date: "THU 07/09/2020",
id: 8
}
];
const printToDom =(divId,textToPrint)=>{
const selectedDiv= document.getElementById(divId);
selectedDiv.innerHTML= textToPrint;
};
const buildTourDates=()=>{
let domString='';
for(let i = 0; i <tourStops.length;i++){
domString += '<div class="container px-lg-5">';
domString += '<div class="row mx-lg-n5">';
domString += `<div class="col py-3 px-lg-5 border">${tourStops[i].date}</div>`;
domString += `<div class="col py-3 px-lg-5 border">${tourStops[i].location}</div>`;
domString += `<div class="col py-3 px-lg-5 border">${tourStops[i].venue}</div>`;
domString += `<a class="btn btn-success border" href="https://www.ticketnetwork.com/en/concerts" role="button" id= "tickets" onclick= "btnPurchase(${tourStops[i].id})" class="btn btn-success border">Purchase Tickets</a>`;
domString += '</div>';
domString += '</div>';
}
printToDom('tourdates',domString)
};
const btnPurchase= (id)=>{
for(let i=0; i < tourStops.length; i++){
if(tourStops[i].id === id) {
return;
}
}
};
const eventsForTickets = () => {
document.getElementById("tickets").addEventListener('click', btnPurchase);
};
const recentEvents = [
{
event: "New Tour!",
para: "text to be inserted into this event. Lorum ipsum to see how more text looks.",
img: ""
},
{
event: "New Album",
para: "text to be inserted into this event. Lorum ipsum to see how more text looks.",
img: ""
},
{
event: "Something",
para: "text to be inserted into this event. Lorum ipsum to see how more text looks.",
img: ""
},
];
const buildEvents = () => {
let domString='';
for(let i = 0; i < recentEvents.length; i++){
domString += `<div class="media">`;
domString += `<img src="..." class="mr-3" alt="...">`;
domString += `<div class="media-body">`;
domString += ` <h5 class="mt-0">${recentEvents[i].event}</h5>`;
domString += `${recentEvents[i].para}`;
domString += `</div>`;
domString += `</div>`;
}
printToDom('newEvents',domString)
};
const initTour=()=> {
buildTourDates(tourStops);
eventsForTickets();
};
const initIndex=()=>{
buildEvents(recentEvents);
}
initTour();
initIndex();
You can use the method window.location.pathname that get the name of the specific page in which you are, according to it then you can do something like that
const pageRoute = window.location.pathname
if(pageRoute == "page-one"){
buildTourDates()
} else if(pageRoute == "page-two"){
buildEvents()
}//so on...

Returning json object nightwatch.js

I want to execute json object like this from my html ul list like this
{name: "Nick", surname:"Kyrgios", age: "22", city: "Sydney"}, {....}, {....}
this is the html part
<html>
<ul>
<li class="user">
<div class="name">Nick</div>
<div class="surname">Kyrgios</div>
<div class="age">22</div>
<div class="city">Sydney</div>
</li>
<li class="user odd">
<div class="name">Nick</div>
<div class="surname">Kyrgios</div>
<div class="age">22</div>
<div class="city">Sydney</div>
</li>
</ul>
</html>
my nightwatch js file
browser.elements('css selector','ul li', function (result) {
els = result.value;
var i = 0;
els.forEach(function(el, j, elz){
browser.elementIdText(el.ELEMENT, function(text) {
console.log(text)
})
})
})
This will execute
{ state: 'success',
sessionId: 'cdfdda85-4348-4692-9ad0-2a5d10080a27',
hCode: 151444186,
value: 'Nick\nKyrgios\n22\nSydney',
class: 'org.openqa.selenium.remote.Response',
status: 0 }
{ state: 'success',
sessionId: 'cdfdda85-4348-4692-9ad0-2a5d10080a27',
hCode: 118749018,
value: 'Nick\nKyrgios\n22\nSydney',
class: 'org.openqa.selenium.remote.Response',
status: 0 }
The main question is how can I change it to normal json format like
{name: "Nick", surname:"Kyrgios", age: "22", city: "Sydney"}, {....}, {....}
Every time you run console.log - you are automatically getting a carriage return. Each call to console.log moves you down one line.
You should be appending the results to a string
var jsonString = "";
els.forEach(function(el,j,elz) {
browser.elementIdText(el.ELEMENT, function(text) {
jsonString += text;
})
console.log(jsonString);

Categories

Resources