Reputation: 87
What is the best method for looping through one object and all of its properties, then moving onto another object and so on...
At the moment, my code only loops through lvlTitle. Whereas I would like to loop through lvlTitle then move on to statement1, statement2, and statement3 and then to the next object.
Thank you.
Here is the javascript:
// Different Levels
var lvls = {
start: {
lvlTitle: 'Lets Start!',
},
lvl1: {
lvlTitle: 'Drinks/Soda/water',
statement1: 'lvl1 info...',
statement2: 'lvl1 more info...',
statement3: 'lvl1 more more info...'
},
lvl2: {
lvlTitle: 'Portion Control/Meals',
statement1: 'lvl2 info...',
statement2: 'lvl2 more info...',
statement3: 'lvl2 more more info...'
},
lvl3: {
lvlTitle: 'Salt',
statement1: 'lvl3 info...',
statement2: 'lvl3 more info...',
statement3: 'lvl3 more more info...'
}
}
// Array of all the levels
var allLvls = [];
// Populate users array
for (var key in lvls) {
allLvls.push(lvls[key]);
}
console.log(allLvls[0].lvlTitle);
let myIndex = 1;
let printText = document.querySelector('.text-container');
printText.innerHTML = allLvls[0].lvlTitle;
function nextLevel() {
printText.innerHTML = allLvls[myIndex].lvlTitle;
myIndex = (myIndex + 1) % (allLvls.length);
};
printText.addEventListener('click', nextLevel);
And here is the Html:
<div class="full-page">
<div class="click-container">
<ul class="text-container">
<li class="text-content">
<div></div>
</li>
</ul>
</div>
Also here is a jsFiddle: Iterate through Array List of Objects
Upvotes: 0
Views: 283
Reputation: 51977
Building on Mark Meyer's answer and Dacre Denny's answer, I offer a recursive generator function that iterates an object's nested values. I also recommend encapsulating the infinite repetition in a higher-order iterator for cleaner code:
const lvls = {start:{lvlTitle:'Lets Start!'},lvl1:{lvlTitle:'Drinks/Soda/water',statement1:'lvl1 info...',statement2:'lvl1 more info...',statement3:'lvl1 more more info...'},lvl2:{lvlTitle:'Portion Control/Meals',statement1:'lvl2 info...',statement2:'lvl2 more info...',statement3:'lvl2 more more info...'},lvl3:{lvlTitle:'Salt',statement1:'lvl3 info...',statement2:'lvl3 more info...',statement3:'lvl3 more more info...'}}
function * deepValuesIterator (o) {
if (typeof o === 'object') {
for (const value of Object.values(o)) {
yield * deepValuesIterator(value)
}
} else {
yield o
}
}
// let's make nextLevel() our infinite iterator
function * nextLevel (levels, generator, element) {
while (true) {
for (const value of generator(levels)) {
yield element.textContent = value
}
}
}
const printText = document.querySelector('.text-container')
const lvlsIterator = nextLevel(lvls, deepValuesIterator, printText)
printText.addEventListener('click', () => lvlsIterator.next())
lvlsIterator.next()
.click-container {
display: flex;
width: 90vw;
height: 12vh;
justify-content: center;
align-items: center;
font-size: calc(14px + (48 - 14) * ((100vw - 300px) / (1600 - 300)));
font-weight: 900;
cursor: pointer;
user-select: none;
}
<div class="full-page">
<div class="click-container">
<ul class="text-container">
<li class="text-content">
<div>
</div>
</li>
</ul>
</div>
</div>
Upvotes: 1
Reputation: 30390
You could use a generator for this special case iteration.
Generators are a relativity new language feature (ES6), that give you the ability to define custom iteration behaviour, allowing you to elegantly iterate through bespoke data structures, data sets, etc.
In ES6, the *
symbol is used to denote that a function is a generator, and the yield
keyword defines how/when your generator function will return a value (or values) back to the iteration sequence being generated.
In the case of your requirements, a generator can be defined and used as follows:
/* Define your iterator as follows. Notice the *, which denotes this
function as a generator
*/
function *iterateData(lvlsData) {
// Iterate the values of your input data, ie the objects with
// `lvlTitle` keys
for (const node of Object.values(lvlsData)) {
// Iterate the values of the that you want your application
// to iterate through sequentially
for(var value of Object.values(node)) {
// The yield keyword means "return this value" to the
// external iteration
yield value
}
}
}
var htmlList = '<ul>'
// Use the generator like so, to produce the following output based on
// your data:
for(var str of iterateData(lvls)) {
htmlList += '<li>' + str + '</li>'
}
htmlList += '</ul>'
let d = document.getElementById('list')
d.innerHTML = htmlList;
Upvotes: 1
Reputation: 92461
You can create a recursive function. It will an object and make a list (or whatever html structure you want to use). In that function look at every property, it's it an object pass that object back into the function, if it's not process it. This will work for objects nested at arbitrary depths and is a good technique to know:
// Different Levels
var lvls = {start: {lvlTitle: 'Lets Start!',},lvl1: {lvlTitle: 'Drinks/Soda/water',statement1: 'lvl1 info...',statement2: 'lvl1 more info...',statement3: 'lvl1 more more info...'},lvl2: {lvlTitle: 'Portion Control/Meals',statement1: 'lvl2 info...',statement2: 'lvl2 more info...',statement3: 'lvl2 more more info...'},lvl3: {lvlTitle: 'Salt',statement1: 'lvl3 info...',statement2: 'lvl3 more info...',statement3: 'lvl3 more more info...'}}
function printProps(obj){
let html = "<ul>"
Object.keys(obj).forEach(key => {
html += '<li>' + key + '</li>'
let next = (typeof obj[key] == 'object' ? printProps(obj[key]) : obj[key])
html += '<li>' + next + '</li>'
})
html += "</ul>"
return html
}
let d = document.getElementById('list')
d.innerHTML = printProps(lvls)
<div id = "list"></div>
Upvotes: 2