Louis
Louis

Reputation: 307

Template literal loop in javascript

I am trying to build an html table out of a JSON file. When i make my table with template literals in javascript, it loops through my whole table and makes a table header for each array in my json.

I have tried to make two functions for my th and my td but that doesn't seem to work.

var petsData = [{
    name: "Purrsloud",
    species: "Cat",
    favFoods: ["wet food", "dry food", "<strong>any</strong> food"],
    birthYear: 2016,
    photo: "https://learnwebcode.github.io/json-example/images/cat-2.jpg"
  },
  {
    name: "Barksalot",
    species: "Dog",
    birthYear: 2008,
    photo: "https://learnwebcode.github.io/json-example/images/dog-1.jpg"
  },
  {
    name: "Meowsalot",
    species: "Cat",
    favFoods: ["tuna", "catnip", "celery"],
    birthYear: 2012,
    photo: "https://learnwebcode.github.io/json-example/images/cat-1.jpg"
  }
];


function foods(foods) {
  return `
<h4>Favorite Foods</h4>
<ul class="foods-list">
${foods.map(food => `<li>${food}</li>`).join("")}
</ul>
`;
}

function petTemplate(pet) {
  return `
    <table>
      <tr>
        <th>Name</th>
        <th>Species</th>
        <th>Birth Year</th>
        <th>Favorite Foods</th>
      </tr>
        <td>${pet.name}</td>
        <td>${pet.species }</td>
        <td>${pet.birthYear}</td>
        <td>${pet.favFoods ? foods(pet.favFoods) : ""}</td>
      <tr>
      </tr>
    </table>
  `;
}

document.getElementById("table").innerHTML = `
  ${petsData.map(petTemplate).join("")}
`;
<div id="table"></div>

It just seems like my petTable function is looping again and again until i get all of the arrays in the json file, but that makes a table header for each for each array of json. I just want one table header and then all of the arrays.

Upvotes: 12

Views: 18906

Answers (3)

Mayur Gupta
Mayur Gupta

Reputation: 519

@constantin answer works much better, But I want a small addition and more logical is that:

We can use a simple function inside ${function_call()}, and return some string literal HTML from the function. Example of this shows below:

let's say api_data.customs is an object

let htmlAdd = function (value) {
  return `<div class="custom-item"> ${value} </div>`;
};

for (let [key, value] of Object.entries(api_data.customs)) {
    console.log(key, value.category_name);
    item_choicesHTML += `<div>hello ${htmlAdd(value)}</div>`;
};

we can't embed loop inside a string literal but yes we can call a function.

Upvotes: 0

Sarah Gro&#223;
Sarah Gro&#223;

Reputation: 10879

"but that doesn't seem to work" is a bit vague, but of course if you keep the header cells in the same place as your rows, they will show up above each row. You can simply put your opening and closing markup into variables and ouput those before and after actually looping over the data with the row-generating function.

There's also an error in your original markup, with the second opening <tr> being right before its closing counterpart instead of before the corresponding <td> tags.

var petsData = [{
    name: "Purrsloud",
    species: "Cat",
    favFoods: ["wet food", "dry food", "<strong>any</strong> food"],
    birthYear: 2016,
    photo: "https://learnwebcode.github.io/json-example/images/cat-2.jpg"
  },
  {
    name: "Barksalot",
    species: "Dog",
    birthYear: 2008,
    photo: "https://learnwebcode.github.io/json-example/images/dog-1.jpg"
  },
  {
    name: "Meowsalot",
    species: "Cat",
    favFoods: ["tuna", "catnip", "celery"],
    birthYear: 2012,
    photo: "https://learnwebcode.github.io/json-example/images/cat-1.jpg"
  }
];

var tableStart = `
  <table>
    <tr>
      <th>Name</th>
      <th>Species</th>
      <th>Birth Year</th>
      <th>Favorite Foods</th>
    </tr>`;
var tableEnd = `
  </table>`;

function foods(foods) {
  return `
<h4>Favorite Foods</h4>
<ul class="foods-list">
${foods.map(food => `<li>${food}</li>`).join("")}
</ul>
`;
}

function petTemplate(pet) {
  return `
      <tr>
        <td>${pet.name}</td>
        <td>${pet.species }</td>
        <td>${pet.birthYear}</td>
        <td>${pet.favFoods ? foods(pet.favFoods) : ""}</td>
      </tr>
  `;
}

document.getElementById("table").innerHTML = `
  ${tableStart}
  ${petsData.map(petTemplate).join("")}
  ${tableEnd}
`;
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="table"></div>

Upvotes: 28

Akash Bhandwalkar
Akash Bhandwalkar

Reputation: 901

If you see at bottom you are using map over your dataset and passing petTemplate as call back function. Which causing repeat execution.

You have to remove the table and th logic out of petTemplate because this is supposed to call for Every element in data

Upvotes: 0

Related Questions