3

So I have the following JS:

function createObject(){
  let object = {
    product1 : "Apple",
    product2 : "Banana",
    product3 : "Cucumber",
    product4 : "Duba",
    product5 : "Emil",
    product6 : "Fidschi",
  }

  return object
}

function setMyProducts(){
   let productNameElements = document.getElementsByClassName('customProductCardName')//$('.customProductCardName')
   let newContents = createObject()
   for(var i = 0; i < productNameElements.length; i++){

     console.log(productNameElements[i].innerHTML)
     console.log(newContents[i].innerHTML)
     productNameElements[i].innerHTML = newContents[i]
   }

 }

As you can see, I have an object containing multiple properties, and I want to copy the values from each property to the innerHTML of the respective member of the HTML Collection I fetched by Classname. However, accessing the JS OBJ with numeric index doesnt work, and therefore this "vanilla" for loop throws an error.

Now I already read on SO about the difference of for...in and for...of loops How to iterate over a JavaScript object? , and basically I wanted to use a for...of loop to iterate over the object, and then increment an extra variable inside the loop to access the respective property of the HTML Collection.

But I dont like this solution much and I wondered whether there is a more elegant solution to this problem. One which would result in less code and ideally without additional helper variables. Would you know of one?

EDIT:

The HTML I'm referencing is here. It is repeated inside my ZURB Foundation framework six times:

<div class="product-card">
  <div class="product-card-thumbnail">
    <a href="#"><img src="https://placehold.it/180x180"/></a>
  </div>
  <h2 class="product-card-title"><a href="#" class="customProductCardName">Product Name</a></h2>
  <span class="product-card-desc">Product Description</span>
  <span class="product-card-price">$9.99</span><span class="product-card-sale">$12.99</span>
  <div class="product-card-colors">
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
  </div>
</div>

The Error thrown is this: "TypeError: newContents[i] is undefined"

Narktor
  • 977
  • 14
  • 34

2 Answers2

4

Once you have the index of the element you're iterating over, you can access the appropriate property on the object by concatenating it (plus one) with product:

function setMyProducts() {
  const obj = {
    product1: "Apple",
    product2: "Banana",
    product3: "Cucumber",
    product4: "Duba",
    product5: "Emil",
    product6: "Fidschi",
  };
  document.querySelectorAll('.customProductCardName')
    .forEach((element, i) => {
      element.textContent = obj['product' + (i + 1)];
    });
}

setMyProducts();
<div class="customProductCardName"></div>
<div class="customProductCardName"></div>
<div class="customProductCardName"></div>
<div class="customProductCardName"></div>
<div class="customProductCardName"></div>
<div class="customProductCardName"></div>
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • This can be further reduced: `forEach((el i) => element.textContent = obj['product' + (i + 1)]);` – GBWDev Aug 13 '19 at 08:15
  • 1
    While *possible*, that code would be very slightly less clear IMO, because it returns an assignment, which is pretty weird (even though `forEach` ignores the returned value). I like following the linting rule of [no-return-assign](https://eslint.org/docs/rules/no-return-assign) – CertainPerformance Aug 13 '19 at 08:16
  • Never seen that rule before but I can see the appeal. – GBWDev Aug 13 '19 at 08:18
0

It will be helpful to you newContents is not array so newConstents[i] will not work. so given the key with dynamic values like below

 productNameElements[i].innerHTML = newContents["product"+(i+1)]

function createObject(){
  let object = {
    product1 : "Apple",
    product2 : "Banana",
    product3 : "Cucumber",
    product4 : "Duba",
    product5 : "Emil",
    product6 : "Fidschi",
  }

  return object
}

function setMyProducts(){
   let productNameElements = document.getElementsByClassName('customProductCardName')//$('.customProductCardName')
   let newContents = createObject()
   for(var i = 0; i < productNameElements.length; i++){

     console.log(productNameElements[i].innerHTML)
     productNameElements[i].innerHTML = newContents["product"+(i+1)]
   }

 }
 setMyProducts()
<div class="product-card">
  <div class="product-card-thumbnail">
    <a href="#"><img src="https://placehold.it/180x180"/></a>
  </div>
  <h2 class="product-card-title"><a href="#" class="customProductCardName">Product Name</a></h2>
  <span class="product-card-desc">Product Description</span>
  <span class="product-card-price">$9.99</span><span class="product-card-sale">$12.99</span>
  <div class="product-card-colors">
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
  </div>
</div>
<div class="product-card">
  <div class="product-card-thumbnail">
    <a href="#"><img src="https://placehold.it/180x180"/></a>
  </div>
  <h2 class="product-card-title"><a href="#" class="customProductCardName">Product Name</a></h2>
  <span class="product-card-desc">Product Description</span>
  <span class="product-card-price">$9.99</span><span class="product-card-sale">$12.99</span>
  <div class="product-card-colors">
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
  </div>
</div>
<div class="product-card">
  <div class="product-card-thumbnail">
    <a href="#"><img src="https://placehold.it/180x180"/></a>
  </div>
  <h2 class="product-card-title"><a href="#" class="customProductCardName">Product Name</a></h2>
  <span class="product-card-desc">Product Description</span>
  <span class="product-card-price">$9.99</span><span class="product-card-sale">$12.99</span>
  <div class="product-card-colors">
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
    <button href="#" class="product-card-color-option"><img src="https://placehold.it/30x30"/></button>
  </div>
</div>
Kalaiselvan
  • 2,095
  • 1
  • 18
  • 31