1

I have json information (like below). I can print the classroom name and level easily. But I don't know how to loop through the students to print that out as well. I am unsure of how to do a foreach loop inside a foreach loop. My HTML isn't set in stone and can be changed a bit if needed.

<div id="results">
    <div class="classroom">
        <div class="cr-name">Name: maths class</div>
        <div class="cr-level">Level: 4</div>
        <div class="students">
            <div class="student">john 19</div>
            <div class="student">Mike 34</div>
            <div class="student">Billy 19</div>
        </div>
    </div><br>
    <div class="classroom">
        <div class="cr-name">Name: English class</div>
        <div class="cr-level">Level: 2</div>
        <div class="students">
            <div class="student">Sam 24</div>
            <div class="student">Timmy 32</div>
            <div class="student">John 19</div>
            <div class="student">Paul 54</div>
        </div>
    </div>
</div><br>

The json data looks like this:

[
  {
    "classroom": "maths class",
    "students": [
      {
        "name": "john",
        "age": 20
      },
      {
        "name": "Mike",
        "age": 34
      },
      {
        "name": "Billy",
        "age": 19
      }
    ],
    "level": 4
  },
  {
    "classroom": "English class",
    "students": [
      {
        "name": "Sam",
        "age": 24
      },
      {
        "name": "Timmy",
        "age": 32
      },
      {
        "name": "John",
        "age": 19
      },
      {
        "name": "Paul",
        "age": 54
      }
    ],
    "level": 2
  }
]

My HTML:

<div id="results">
</div>

My Javascript (where data is that json information above):

if(typeof data !== 'undefined' && data.length > 0) {
    data.forEach((myclass, idx) => {
        $("#results").append(`
        <div class="classroom">
            <div class="cr-name">Name: ${data.classroom}</div>
            <div class="cr-level">Level: ${data.level}</div>
        </div><br>
      `);
    });
}
Jackie
  • 372
  • 5
  • 16

2 Answers2

1

Take the students array and .map each item to an HTML string, eg <div class="student">john 19</div>, then join it together:

const data = [
  {
    "classroom": "maths class",
    "students": [
      {
        "name": "john",
        "age": 20
      },
      {
        "name": "Mike",
        "age": 34
      },
      {
        "name": "Billy",
        "age": 19
      }
    ],
    "level": 4
  },
  {
    "classroom": "English class",
    "students": [
      {
        "name": "Sam",
        "age": 24
      },
      {
        "name": "Timmy",
        "age": 32
      },
      {
        "name": "John",
        "age": 19
      },
      {
        "name": "Paul",
        "age": 54
      }
    ],
    "level": 2
  }
]

data.forEach(({ classroom, level, students }) => {
    $("#results").append(`
    <div class="classroom">
        <div class="cr-name">Name: ${classroom}</div>
        <div class="cr-level">Level: ${level}</div>
        <div class="students">
            ${
              students
                .map(({ name, age }) => `<div class="student">${name} ${age}</div>`)
                .join('')
            }
        </div>
    </div><br>
  `);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="results"></div>

That's if the input data is trustworthy. If it isn't trustworthy, writing such an HTML string directly could result in arbitrary code execution. If that's something you need to protect against, make sure to remove all <> brackets first:

name.replace(/[<>]/g, '')
age.replace(/[<>]/g, '')
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Entire data is not trustworthy. can u show me how to do the replace thing – Jackie Apr 22 '20 at 07:55
  • You just have to use the code at the bottom of the answer - insert the variables while calling `replace`, instead of just inserting the plain variables – CertainPerformance Apr 22 '20 at 07:57
  • also if `name` is `some Аnd thing` it doesn't get printed out? – Jackie Apr 22 '20 at 08:01
  • If it contains HTML entities, you can unescape them with a method in [this post](https://stackoverflow.com/questions/1912501/unescape-html-entities-in-javascript). It's kinda weird for untrustworthy data to deliberately send HTML entities like that, like it's *deliberately* trying to get you to concatenate an HTML string directly, which is unsafe – CertainPerformance Apr 22 '20 at 09:20
  • Sorry, I mean when the string contains HTML, the javascript doesn't build print it out. When its normal text then it does print it – Jackie Apr 22 '20 at 10:11
  • If the string contains HTML, but the string is also untrustworthy, you should not be trying to render the HTML, because you could be opening yourself up to arbitrary code execution. For example, if this data is fetched by a network request, and a user of your website runs the code with the HTML directly inserted, then that user's sensitive login information could be sent to a malicious actor. – CertainPerformance Apr 22 '20 at 10:36
  • You can either be unsafe, and render the HTML (by directly concatenating the string gotten by the API), or you can be safe, and only render text. – CertainPerformance Apr 22 '20 at 10:36
  • I will escape the HTML. Horever the issue with the code you provided is if the name is `math class` it prints out on the screen. If the name is `some Аnd thing` it skips the entire json information. – Jackie Apr 22 '20 at 11:12
  • If you have HTML entities you need to replace, then see the link I posted above - https://stackoverflow.com/questions/1912501/unescape-html-entities-in-javascript Using any of the methods there, you can turn HTML entities into normal characters, and it should work – CertainPerformance Apr 22 '20 at 11:20
0

Hope it will help you.

if(typeof data !== 'undefined' && data.length > 0) {

    data.forEach((myclass, idx) => {
        studentsMath  = myclass.students;

        studentsMath.forEach((val, id) => {

            $("#results").append(`
            <div class="classroom">
                <div class="cr-name">Name: ${val.name}</div>
                <div class="cr-level">Level: ${myclass.level}</div>
            </div><br>
          `);
        })

    });
}