2

I have an existing table. I have the td cells displayed as blocks intentionally. :) My goal is to add labels inside each of the td's by creating spans with a specific class, then prepend them to the table cell. I'm using an array of objects with the label data, an 'icon' and a 'name'.

The Goal

I'm having trouble applying the icons individually to the td's. They all get grouped together on each cell.

enter image description here

A few issues I'm trying to solve:

  1. Add each object (one icon and one label) to each cell
  2. When creating the elements, add an icon class to the icon span and an label class to the label span.
  3. Apply them appropriately in the order shown in the object

I've tried a bunch of different things (see code comments) and lots of good posts here on SO but this function seems to get me the closest to my goal. Any help is very much appreciated.

let items = [{
    id: "🐌",
    name: "snail"
  },
  {
    id: "🐜",
    name: "ant"
  },
  {
    id: "🪲",
    name: "beetle"
  },
  {
    id: "🐝",
    name: "honeybee"
  },
  {
    id: "🕷",
    name: "spider"
  }
];

function createLabel(obj) {
  // let loc = document.getElementsByTagName("#profiles td");
  let loc = document.querySelectorAll("#profiles td");

  if (typeof obj !== "undefined" && obj !== null) {
    // loop through td's
    for (let i = 0; i < loc.length; i++) {
      // apply object data
      obj.forEach((item) => {
        Object.values(item).forEach((text) => {
          // loc.prepend(span);

          // I also tried my for loop here with similar weird results

          let span = document.createElement("span");
          let textNode = document.createTextNode(text);
          // 'id' should get .icon
          // 'name' should get .label
          span.className = 'icon';
          span.append(textNode);
          loc[i].prepend(span);
        });
      });
    }
  }
}
createLabel(items);
<table id="profiles">
  <tr>
    <td>Snail Stuff</td>
    <td>Ant Stuff</td>
    <td>Beetle Stuff</td>
    <td>Honeybee Stuff</td>
    <td>Spider Stuff</td>
  </tr>
</table>

2 Answers 2

2

You were using document.querySelectorAll. You can simply use document.querySelector to get the table and run a for of loop to append the element to the table

let items = [
  { id: "🐌", name: "snail", text: "Snail Stuff" },
  { id: "🐜", name: "ant", text: "Ant Stuff" },
  { id: "🪲", name: "beetle", text: "Beetle Stuff" },
  { id: "🐝", name: "honeybee", text: "Honeybee Stuff" },
  { id: "🕷", name: "spider", text: "Spider Stuff" }
];

function createLabel(obj) {
  const loc = document.querySelector("#profileRow");
  const elements = [];

  for (const item of obj) {
    const el = document.createElement("td");
    el.innerHTML = `<span class='icon'>${item.id}</span> <span class='label'>${item.name}</span> ${item.text}`;
    elements.push(el);
  }

  loc.append(...elements);
}
createLabel(items);
td {
  display: block;
  border: 1px solid #ccc;
}
span {
  display: inline-block;
}
.icon {
  background: yellow;
  width: 3rem;
  text-align: center;
}
.label {
  font-weight: bold;
  width: 6rem;
}


.pie {
  margin-top: 4rem;
}
<!DOCTYPE html>
<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
  </head>

  <body>
    <table id="profiles">
      <tr id="profileRow"></tr>
    </table>
  </body>
</html>

Sign up to request clarification or add additional context in comments.

8 Comments

It's better to explain what your code is doing differently, where the OP went wrong, etc., rather than just a code dump.
@LeeTaylor Yes done
OK, I gotcha. Thank you! I mistakenly was trying to loop over the table cells then loop over the object and insert the data. Classic case of overthinking the problem. I like the use of template literals to make it even cleaner.
@Inder I like this answer but how would it work with my html? There will be existing data in these cells and every 'row' will get the same labels. Using this method ADDS a td which becomes another set of 'rows' which I want to avoid. I want to just add the two spans inside the before the existing data.
@carbonspace there is only one row, inside that row more cells are being added. I'm using td tags not tr. I'm appending cells on a single row.
|
1

I think the issue is that you're looping twice over the elements. With the first for it should be enough

This is my go:

let items = [{
    id: "🐌",
    name: "snail"
  },
  {
    id: "🐜",
    name: "ant"
  },
  {
    id: "🪲",
    name: "beetle"
  },
  {
    id: "🐝",
    name: "honeybee"
  },
  {
    id: "🕷",
    name: "spider"
  },
];

//created a function so that we don't repeat the span creation
function createSpan(text, className) {
  let span = document.createElement('span')
  span.className = className;
  let textNode = document.createTextNode(text)
  span.append(textNode)
  return span
}

function createLabel(obj) {
  // let loc = document.getElementsByTagName("td");
  let loc = document.querySelectorAll("#profiles td");

  if (typeof obj !== "undefined" && obj !== null) {
    // loop through td's
    for (let i = 0; i < loc.length; i++) {
      // apply object data
      // loc.prependspan;
      //destructure the item so that we get its properties, it's the same as doing const id = items[i].id and const name=items[i].name but all in one line!
      const {
        id,
        name
      } = items[i]
      const iconSpan = createSpan(id, 'icon')
      // 'id' should get .icon
      // 'name' should get .label

      let labelSpan = createSpan(name, 'label')
      loc[i].prepend(iconSpan, labelSpan);
      // loc[i].insertAdjacentHTML('afterbegin', span);
      ;
    }
  }
}
createLabel(items);
<table id="profiles">
  <tr>
    <td>Snail Stuff</td>
    <td>Ant Stuff</td>
    <td>Beetle Stuff</td>
    <td>Honeybee Stuff</td>
    <td>Spider Stuff</td>
  </tr>
</table>

2 Comments

That doesn't seem to be as OP wanted.
Nice. I wanted to try and wrap it all in one function but this answer works [ codepen.io/carbonspace/pen/NWyxWqa ] and it's not a bad way to go about it. Interesting way to get the object data and a good solution. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.