Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Problem creating buttons through .map loop

I’m trying to create a basic inventory in JavaScript. I would like to add items to an array which would be the player inventory. What’s inside the inventory array would be displayed on multiple divs (one per item). I’ve already starting experiencing and getting the basics to work, but I wanted to elaborate a bit and create buttons per each item in the item list so as to later use the buttons to add the items to the inventory.

I started by selecting my HTML divs and creating a basic itemList array and a playerInv empty array:

const container = document.querySelector('.container');
const inventory = document.querySelector('.inventory');
const invItem = document.querySelectorAll('.grid-item');

const itemList = [{
    id: 1,
    name: "Coke Bottle",
    quality: "usable"
  },
  {
    id: 6,
    name: "Pair of Jeans",
    quality: "pants"
  }
]

// Player inventory, is by default empty.
const playerInv = []

const itemBtnContainer = document.createElement("div");
itemBtnContainer.classList.add("item-add-btn-ctn");
container.appendChild(itemBtnContainer);

let itemBtn;

function addItemBtn() {
  itemList.map((item) => {
    itemBtn = document.createElement("button");
    itemBtn.classList.add("item-add-btn");
    itemBtnContainer.appendChild(itemBtn);
    itemBtn.innerText += item.name;
  })
}
addItemBtn();
<div class="container">
  CONT
  <div class="inventory">
    <div class="inventory-left">
      <div class="inventory-left-title">Your inventory</div>
      <div class="inventory-left-grid">
        <div class="grid-item"></div>
        <div class="grid-item"></div>
        <div class="grid-item"></div>
        <div class="grid-item"></div>
        <div class="grid-item"></div>
        <div class="grid-item"></div>
        <div class="grid-item"></div>
        <div class="grid-item"></div>
        <div class="grid-item"></div>
        <div class="grid-item"></div>
      </div>
    </div>
    <div class="inventory-right"></div>
  </div>
</div>

So, in order to create my buttons my idea was to loop through my itemList array with map. Each itemList item would create a button with a class of "item-add-btn" and inside the button would be displayed the name of the item.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Visually, it works. I have 6 buttons because of the 6 itemList items, but because I created the buttons in my loop I can’t access them outside of the loop. Indeed, if I console.log(itemBtn) it returns ‘undefined’, so I can’t create an onClick function with addEventListener in order to later write my addItemToInv() function.
I understand why it doesn’t work, but I really don’t know what else I can do to get to the same results AND be able to use my buttons.

I don’t even know what else I can try since it’s a very specific need.

>Solution :

First you should be using for .. of or Array.prototype.forEach because .map builds a new array which you are discarding.

Second, make a createButton function that returns the button so you can store it to a value –

function createButton(item) {
  const itemBtn = document.createElement("button")
  itemBtn.type = "button"
  itemBtn.classList.add("item-add-btn")
  itemBtn.innerText += item.name
  return itemBtn
}

Now you can loop –

for (const item of itemList) {
  // create button reference
  const button = createButton(item)

  // add click handler
  button.addEventListener("click", ...)

  // append button to container
  itemBtnContainer.appendChild(button)
}

Here’s a full working demo –

const inventory = []

const itemList = [{id:1,name: "Coke Bottle",quality: "usable"},{id: 6,name: "Pair of Jeans",quality: "pants"}]

function renderInventory() {
  document
  .querySelector("#inventory")
  .textContent = `inventory: ${JSON.stringify(inventory, null, 2)}`
}

function createButton(text, onClick) {
  const e = document.createElement("button")
  e.type = "button"
  e.textContent = text
  e.addEventListener("click", onClick)
  return e
}

function addToInv(item) {
  return event => {
    inventory.push(item)
    renderInventory()
  }
}

renderInventory()

for (const item of itemList)
  document.body.appendChild(createButton(item.name, addToInv(item)))
#inventory {
  padding: 1rem;
  background-color: #eee;
  font-family: monospace;
}
<pre id="inventory"></pre>
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading