Neha Chaudhary
Neha Chaudhary

Reputation: 1259

How do I iterate over a sub array dictionary in json file using vanilla javascript?

script.js

fetch("pizzas.json").then((response) =>
  response.json().then((data) => {
    let jsonSize = data.length;

    let htmlContent = "";
    for (let i = 0; i < jsonSize; i++) {
      let id = data[i].id;
      let name = data[i].name;
      let img = data[i].img;
      let price = data[i].price;
      let sizes = data[i].sizes;
      let description = data[i].description;
      let cheese = data[i].cheese;
      console.log(i);
      htmlContent += `
           <div class="column-pizza">
            <a href="">
              <div class="pizza-item--img">
                <img src="${img}" id="pizza-img-${i}" />
              </div>
              <div class="pizza-item--add" id="selected-${i}">Add</div>
            </a>
            <div class="pizza-item--price" id="pizza-price-${i}">₹${price}</div>
            <div class="pizza-item--name" id="pizza-name-${i}">${name}</div>
            <div class="pizza-item--desc" id="pizza-desc-${i}">${description}</div>
            <div class="pizza-item--sizes" id="pizza-size-${i}">
                <input
                  type="radio"
                  id="small-1"
                  name="sizes-1"
                  value="small"
                />
                <label for="small">${sizes[i]}</label>
                <input
                  type="radio"
                  id="medium-1"
                  name="sizes-1"
                  value="medium"
                />
                <label for="medium">${sizes[i + 1]}</label>
                <input
                  type="radio"
                  id="large-1"
                  name="sizes-1"
                  value="large"
                />
                <label for="large">${sizes[i + 2]}</label>
              </div>
        </div>`;
     }
    document.querySelector("#root").innerHTML = htmlContent;
  })
);

pizzas.json

[
  {
    "id": 1,
    "name": "Tandoori Paneer",
    "img": "/images/pizza.png",
    "price": 200,
    "sizes": [{ "Small": 0 }, { "Medium": 100 }, { "Large": 200 }],
    "description": "Spiced paneer, Onion, Green Capsicum & Red Paprika in Tandoori Sauce",
    "cheese": [{ "Regular": 0 }, { "Extra Cheese": 100 }, { "No Cheese": 0 }]
  },
  {
    "id": 2,
    "name": "Veggie Supreme",
    "img": "images/pizza.png",
    "price": 250,
    "sizes": [{ "Small": 0 }, { "Medium": 100 }, { "Large": 200 }],
    "description": "Black Olives, Green Capsicum, Mushroom, Onion, Red Paprika, Sweet Corn",
    "cheese": [{ "Regular": 0 }, { "Extra Cheese": 100 }, { "No Cheese": 0 }]
  },
  {
    "id": 3,
    "name": "Veg Exotica",
    "img": "images/pizza.png",
    "price": 300,
    "sizes": [{ "Small": 0 }, { "Medium": 100 }, { "Large": 200 }],
    "description": "Baby Corn, Black Olives, Green Capsicum, Jalapeno, Red Capsicum",
    "cheese": [{ "Regular": 0 }, { "Extra Cheese": 100 }, { "No Cheese": 0 }]
  }
]

MY DOUBT:

  1. How do I access the size array of objects in pizzas.json and use it in script.js
  2. Also, when I'm using ${size[i]}, ${size[i+1]}, ${size[i+2]}, it doesn't show the correct output as when i becomes greater than 0, it refers size[1], size[2] and size[3] where size[3] doesn't exist.

    MY TAKE ON:
    For the indexing issue for size[], can I use javascript code between the htmlContent?
    Please help.

Upvotes: 0

Views: 114

Answers (3)

AL-zami
AL-zami

Reputation: 9066

Source of your problem:


Extended array size doesn't need to hold any value nor it need to exist in javascript. Javascript allow you to access any index even if it does not exists. See the following example.

let arr = [1,2]

arr[2] // undefined, we can access index 2 even if this array doesn't have any value at index 2

Now, in your code you have written a for loop on array size which is using a variable called i. So let's say you have a json array which length is 5. So during iteration, when i == 5, then [i+1] will be 6 and [i+2] will be 7. But sizes array does not have this indexes.

Solution approaches to consider:


You can use a second for loop like the following for each iteration of outer loop.

for(let i=0; i<jsonSize; i++) {
    for (let j=0; j<json[i].sizes; j++) {
        // do things here
    }
}

You can also simply use Array.prototype.forEach instead of for loops. In this case you need to use one foreach inside another.

JsonArr.forEach((eachElementObj,index)=>{
    //do outer loop things
    let sizes = eachElementObj.sizes
    sizes.forEach(element=>{
                    // do things 
    })
})

Upvotes: 0

DecPK
DecPK

Reputation: 25408

You can't use index i as it is representing an object in pizza array. It is fine for index === 0 but whent the index exceeds 0 then it will access the elements in sizes array beyond its length.

Let say i is 1 then

  • i --> 1
  • i + 1 --> 2
  • i + 1 --> 3

and sizes array doesn't have any element with index 3. It has only index upto 2(zero-based)

"sizes": [{ "Small": 0 }, { "Medium": 100 }, { "Large": 200 }]

You need to take another index variable let say j and increment it.

let j = 0;

.
.
.

<div class="pizza-item--sizes" id="pizza-size-${i}">
                <input
                  type="radio"
                  id="small-1"
                  name="sizes-1"
                  value="small"
                />
                <label for="small">${sizes[j]}</label>
                <input
                  type="radio"
                  id="medium-1"
                  name="sizes-1"
                  value="medium"
                />
                <label for="medium">${sizes[j + 1]}</label>
                <input
                  type="radio"
                  id="large-1"
                  name="sizes-1"
                  value="large"
                />
                <label for="large">${sizes[j + 2]}</label>
              </div>

If you want to access the property and its value in sizes array, then it would be better not to hardcode it and use it as follows(caution: only select the first property). It will work if you change the size name like larget to extraLarge.

const sizes = [{ Small: 0 }, { Medium: 100 }, { Large: 200 }];

// Object.keys - returns the keys from the respective object
for (let j = 0; j < sizes.length; ++j) {
  console.log(
    `${Object.keys(sizes[j])[0]} - ${sizes[j][Object.keys(sizes[j])[0]]}`
  );
}

Upvotes: 1

Yadab
Yadab

Reputation: 1883

You can't access sizes with the index of parent loop. It has to use its own loop. If the data is constant then you can do something like this to achieve it.

const data = [
  {
    "id": 1,
    "name": "Tandoori Paneer",
    "img": "/images/pizza.png",
    "price": 200,
    "sizes": [{ "Small": 0 }, { "Medium": 100 }, { "Large": 200 }],
    "description": "Spiced paneer, Onion, Green Capsicum & Red Paprika in Tandoori Sauce",
    "cheese": [{ "Regular": 0 }, { "Extra Cheese": 100 }, { "No Cheese": 0 }]
  },
  {
    "id": 2,
    "name": "Veggie Supreme",
    "img": "images/pizza.png",
    "price": 250,
    "sizes": [{ "Small": 0 }, { "Medium": 100 }, { "Large": 200 }],
    "description": "Black Olives, Green Capsicum, Mushroom, Onion, Red Paprika, Sweet Corn",
    "cheese": [{ "Regular": 0 }, { "Extra Cheese": 100 }, { "No Cheese": 0 }]
  },
  {
    "id": 3,
    "name": "Veg Exotica",
    "img": "images/pizza.png",
    "price": 300,
    "sizes": [{ "Small": 0 }, { "Medium": 100 }, { "Large": 200 }],
    "description": "Baby Corn, Black Olives, Green Capsicum, Jalapeno, Red Capsicum",
    "cheese": [{ "Regular": 0 }, { "Extra Cheese": 100 }, { "No Cheese": 0 }]
  }
];

let jsonSize = data.length;

let htmlContent = "";
for (let i = 0; i < jsonSize; i++) {
  let id = data[i].id;
  let name = data[i].name;
  let img = data[i].img;
  let price = data[i].price;
  let sizes = data[i].sizes;
  let description = data[i].description;
  let cheese = data[i].cheese;
  htmlContent += `
       <div class="column-pizza">
        <a href="">
          <div class="pizza-item--img">
            <img src="${img}" id="pizza-img-${i}" />
          </div>
          <div class="pizza-item--add" id="selected-${i}">Add</div>
        </a>
        <div class="pizza-item--price" id="pizza-price-${i}">₹${price}</div>
        <div class="pizza-item--name" id="pizza-name-${i}">${name}</div>
        <div class="pizza-item--desc" id="pizza-desc-${i}">${description}</div>
        <div class="pizza-item--sizes" id="pizza-size-${i}">
            <input
              type="radio"
              id="small-1"
              name="sizes-1"
              value="small"
            />
            <label for="small">${sizes[0].Small}</label>
            <input
              type="radio"
              id="medium-1"
              name="sizes-1"
              value="medium"
            />
            <label for="medium">${sizes[1].Medium}</label>
            <input
              type="radio"
              id="large-1"
              name="sizes-1"
              value="large"
            />
            <label for="large">${sizes[2].Large}</label>
          </div>
    </div>`;
 }
document.querySelector("#root").innerHTML = htmlContent;
<div id="root"></div>

And if you want to render the name within the radio button then you can do like this.

const data = [
  {
    "id": 1,
    "name": "Tandoori Paneer",
    "img": "/images/pizza.png",
    "price": 200,
    "sizes": [{ "Small": 0 }, { "Medium": 100 }, { "Large": 200 }],
    "description": "Spiced paneer, Onion, Green Capsicum & Red Paprika in Tandoori Sauce",
    "cheese": [{ "Regular": 0 }, { "Extra Cheese": 100 }, { "No Cheese": 0 }]
  },
  {
    "id": 2,
    "name": "Veggie Supreme",
    "img": "images/pizza.png",
    "price": 250,
    "sizes": [{ "Small": 0 }, { "Medium": 100 }, { "Large": 200 }],
    "description": "Black Olives, Green Capsicum, Mushroom, Onion, Red Paprika, Sweet Corn",
    "cheese": [{ "Regular": 0 }, { "Extra Cheese": 100 }, { "No Cheese": 0 }]
  },
  {
    "id": 3,
    "name": "Veg Exotica",
    "img": "images/pizza.png",
    "price": 300,
    "sizes": [{ "Small": 0 }, { "Medium": 100 }, { "Large": 200 }],
    "description": "Baby Corn, Black Olives, Green Capsicum, Jalapeno, Red Capsicum",
    "cheese": [{ "Regular": 0 }, { "Extra Cheese": 100 }, { "No Cheese": 0 }]
  }
];

let jsonSize = data.length;

let htmlContent = "";
for (let i = 0; i < jsonSize; i++) {
  let id = data[i].id;
  let name = data[i].name;
  let img = data[i].img;
  let price = data[i].price;
  let sizes = data[i].sizes;
  let description = data[i].description;
  let cheese = data[i].cheese;
  htmlContent += `
       <div class="column-pizza">
        <a href="">
          <div class="pizza-item--img">
            <img src="${img}" id="pizza-img-${i}" />
          </div>
          <div class="pizza-item--add" id="selected-${i}">Add</div>
        </a>
        <div class="pizza-item--price" id="pizza-price-${i}">₹${price}</div>
        <div class="pizza-item--name" id="pizza-name-${i}">${name}</div>
        <div class="pizza-item--desc" id="pizza-desc-${i}">${description}</div>
        <div class="pizza-item--sizes" id="pizza-size-${i}">
            <input
              type="radio"
              id="small-1"
              name="sizes-1"
              value="small"
            />
            <label for="small">${Object.keys(sizes[0])[0]}</label>
            <input
              type="radio"
              id="medium-1"
              name="sizes-1"
              value="medium"
            />
            <label for="medium">${Object.keys(sizes[1])[0]}</label>
            <input
              type="radio"
              id="large-1"
              name="sizes-1"
              value="large"
            />
            <label for="large">${Object.keys(sizes[2])[0]}</label>
          </div>
    </div>`;
 }
document.querySelector("#root").innerHTML = htmlContent;
<div id="root" />

Upvotes: 1

Related Questions