Vaggelis
Vaggelis

Reputation: 1011

Create elements by looping a javascript object

Lets say we have an array of objects and we loop through it and create a div in every iteration.

How could we take the property ol (which is also an array of objects) in every iteration and create an <ol> inside the div for every object in it, with as many <li>'s as the number in the property li. Also, text inside the li should be the text of the property title so it should look like this:

enter image description here

I'm hitting my head to solve it but my noobness doesn't let me. I tried another loop of the ol object inside the outer loop, but I cant get it right.

var array_of_objects = [{
  "name": "john",
  "job": "pilot",
  "email": "[email protected]",
  "ol": [{
    "li": 6,
    "title": "6 li's"
  }, {
    "li": 2,
    "title": "2 li's"
  }, {
    "li": 5,
    "title": "5 li's"
  }]
}, {
  "name": "mark",
  "job": "engineer",
  "email": "[email protected]",
  "ol": [{
    "li": 2,
    "title": "2 li's"
  }, {
    "li": 7,
    "title": "7 li's"
  }, {
    "li": 2,
    "title": "2 li's"
  }, {
    "li": 1,
    "title": "1 li's"
  }]
}, {
  "name": "george",
  "job": "chef",
  "email": "[email protected]",
  "ol": [{
    "li": 1,
    "title": "1 li's"
  }, {
    "li": 3,
    "title": "3 li's"
  }, {
    "li": 4,
    "title": "4 li's"
  }, {
    "li": 3,
    "title": "3 li's"
  }, {
    "li": 3,
    "title": "3 li's"
  }]
}]

function iterate(arr) {
  arr.forEach(i => {
    var name = i.name;
    var job = i.job;
    var email = i.email;
    var ol_li = i.ol_li;
    var str = `<div>
    <span>${name}</span>
    <span>${job}</span>
    <span>${email}</span>
    <span>ol's should be placed here</span>
    </div>`
    $("body").append(str);
  })
}

iterate(array_of_objects)
div {
  display: flex;
  flex-direction: column;
  border: thin solid black;
  margin: 0.4em;
  padding: 0.2em;
}

span:not(:nth-child(4)) {
  display: flex;
  flex-direction: column;
  border: thin solid red;
  margin: 0.2em;
  padding: 0.2em;
}

span:nth-child(4) {
  display: flex;
  flex-direction: row;
  margin: 0.4em;
  padding: 0.2em;
}

ol {
  border: thin solid blue;
  margin: 0.2em;
}

li {
  margin: 0.2em;
}
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>

Upvotes: 1

Views: 885

Answers (2)

Rory McCrossan
Rory McCrossan

Reputation: 337560

To do what you require you can use map() to loop through the ol array of each object and create a HTML string which can be appended to the div you create.

Note the use of fill() in the example below to create the required number of li elements with the same content.

Also note that the same approach can be used to both tidy the code and improve performance as it means you only append to the DOM once when the loop completes, instead of within each loop iteration.

Try this:

var array_of_objects = [{name:"john",job:"pilot",email:"[email protected]",ol:[{li:6,title:"6 li's"},{li:2,title:"2 li's"},{li:5,title:"5 li's"}]},{name:"mark",job:"engineer",email:"[email protected]",ol:[{li:2,title:"2 li's"},{li:7,title:"7 li's"},{li:2,title:"2 li's"},{li:1,title:"1 li's"}]},{name:"george",job:"chef",email:"[email protected]",ol:[{li:1,title:"1 li's"},{li:3,title:"3 li's"},{li:4,title:"4 li's"},{li:3,title:"3 li's"},{li:3,title:"3 li's"}]}];

function htmlFromData(arr) {
  return arr.map(obj => {
    let olHtml = obj.ol.map(ol => `<ol>${(new Array(ol.li)).fill(`<li>${ol.title}</li>`).join('')}</ol>`).join('');
    return `<div>
      <span>${obj.name}</span>
      <span>${obj.job}</span>
      <span>${obj.email}</span>
      <span>${olHtml}</span>
    </div>`    
  }).join('');
}

$("body").append(htmlFromData(array_of_objects));
div {
  display: flex;
  flex-direction: column;
  border: thin solid black;
  margin: 0.4em;
  padding: 0.2em;
}

span:not(:nth-child(4)) {
  display: flex;
  flex-direction: column;
  border: thin solid red;
  margin: 0.2em;
  padding: 0.2em;
}

span:nth-child(4) {
  display: flex;
  flex-direction: row;
  margin: 0.4em;
  padding: 0.2em;
}

ol {
  border: thin solid blue;
  margin: 0.2em;
}

li {
  margin: 0.2em;
}
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>

Upvotes: 0

thepouria
thepouria

Reputation: 53

I think this should do the trick :

  • Map throw ol array and put single li item in a variable;
  • Use repeat() function to print it in ol variable

var array_of_objects = [
  {
    "name":"john",
    "job":"pilot",
    "email":"[email protected]",
    "ol":[
      {"li":6,"title":"6 li's"},
      {"li":2,"title":"2 li's"},
      {"li":5,"title":"5 li's"}
    ]
  },
  {
    "name":"mark",
    "job":"engineer",
    "email":"[email protected]",
    "ol":[
      {"li":2,"title":"2 li's"},
      {"li":7,"title":"7 li's"},
      {"li":2,"title":"2 li's"},
      {"li":1,"title":"1 li's"}
    ]
  },
  {
    "name":"george",
    "job":"chef",
    "email":"[email protected]",
    "ol":[
      {"li":1,"title":"1 li's"},
      {"li":3,"title":"3 li's"},
      {"li":4,"title":"4 li's"},
      {"li":3,"title":"3 li's"},
      {"li":3,"title":"3 li's"}
    ]
  }
]

  function iterate(arr){

  arr.forEach(i => {

  var name = i.name;
  var job = i.job;
  var email = i.email;
  var ol_li = i.ol;
  var list = "";
  var ol = ol_li.forEach(o=>{
     l = `<li>${o.title}</li>`
     list = `${list} <ol> ${l.repeat(o.li)} </ol>`

  })
  var str = `<div>
  <span>${name}</span>
  <span>${job}</span>
  <span>${email}</span>
  <span>${list}</ol>
  </div>`

  $("body").append(str);

  })

  }

  iterate(array_of_objects)
div{
  display:flex;
  flex-direction:column;
  border:thin solid black;
  margin:0.4em;
  padding:0.2em;
}
span:not(:nth-child(4)){
  display:flex;
  flex-direction:column;
  border:thin solid red;
  margin:0.2em;
  padding:0.2em;
}
span:nth-child(4){
  display:flex;
  flex-direction:row;
  margin:0.4em;
  padding:0.2em;
}
ol{
  border:thin solid blue;
  margin:0.2em;
}
li{
  margin:0.2em;
}
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
</head>
<body>
</body>
</html>

Upvotes: 2

Related Questions