Home > Software engineering >  Display object by its property value
Display object by its property value

Time:05-28

I am still learning Javascript, and I have data and trying to to display by its category. I'm confused which method to use to achieved that. Here is my object

const data = [
  {
     category: "sports",
     items: "shoes",
     price: 599,
  },
  {
     category: "electronics",
     items: "phones",
     price: 898,
  },
  {
     category: "sports",
     items: "shirt",
     price: 788,
  },
  {
     category: "sports",
     items: "ball",
     price: 455,
  },
  {
     category: "electronics",
     items: "laptop",
     price: 999,
  },
  {
     category: "beauty",
     items: "lipstick",
     price: 888,
  },
];

The result that I want is more or less like the code snippet below. And thank for your help. I hope you guys understand, because my English is not good enough. Edited, the data is dynamic from users input

div{
  display: flex
}

section{
  border: 1px solid red
}
<section>
  <h1>electronics</h1>
  <div>
    <p>phones</p>
    <p>898</p>
  </div>
  <div>
    <p>laptop</p>
    <p>999</p>
  </div>
</section>

<section>
  <h1>sports</h1>
  <div>
    <p>shoes</p>
    <p>599</p>
  </div>
  <div>
    <p>shirt</p>
    <p>788</p>
  </div>
  <div>
    <p>ball</p>
    <p>455</p>
  </div>
</section>

<section>
  <h1>beauty</h1>
  <div>
    <p>lipstick</p>
    <p>888</p>
  </div>
</section>

CodePudding user response:

Make an object of categories with the value of an array consisting of an object made of the name & price of the product, And at the end just loop through the keys of the object and do the DOM manipulations,

const data = [
  {
    category: "sports",
    items: "shoes",
    price: 599,
  },
  {
    category: "electronics",
    items: "phones",
    price: 898,
  },
];

const categorys = {};
data.forEach((product) => {
  let category = product.category;
  if (!categorys[category]) categorys[category] = [];
  categorys[category].push(product);
});

for (category in categorys) {
  console.log(categorys[category]);
  //do dom manipulation here,
  //the best thing to do would be to create the element
  //and update the dom just once after the loop ends
}

CodePudding user response:

You can do something like this.

Basically the idea is to transform you array into an object of this form

{
  "category1": [{}, {}] //item with category1,
  "category2": [{}, {}] //item with category2,
}

the syntax

return {
   ...res,
   [item.category]: [...(res[item.category] || []), item]
  }

means that it return all previously category in the object (...res)

for the current category it takes all the items in that category (res[item.category]) or empty array if is not defined and set a new array with the previous values plus the current one

const data = [
  {
     category: "sports",
     items: "shoes",
     price: 599,
  },
  {
     category: "electronics",
     items: "phones",
     price: 898,
  },
  {
     category: "sports",
     items: "shirt",
     price: 788,
  },
  {
     category: "sports",
     items: "ball",
     price: 455,
  },
  {
     category: "electronics",
     items: "laptop",
     price: 999,
  },
  {
     category: "beauty",
     items: "lipstick",
     price: 888,
  },
];

//first group by category
const grouppedByCategory = data.reduce((res, item) => {
  
  return {
   ...res,
   [item.category]: [...(res[item.category] || []), item]
  }

}, {})


//then transform your groupped elements into html
const html = Object.entries(grouppedByCategory).map(([cat, products]) => `<section>
  <h1>${cat}</h1>
  ${products.map(({price, items}) => `<div>
    <p>${items}</p>
    <p>${price}</p>
  </div>`).join('') }
</section>`).join('')

document.getElementById('container').innerHTML = html
div{
  display: flex
}

section{
  border: 1px solid red
}
<main id="container"></main>

CodePudding user response:

Here is a simple example of how you could create a new array with the values you wanted using array.filter()

const data = [
  {
     category: "sports",
     items: "shoes",
     price: 599,
  },
  {
     category: "electronics",
     items: "phones",
     price: 898,
  },
  {
     category: "sports",
     items: "shirt",
     price: 788,
  },
  {
     category: "sports",
     items: "ball",
     price: 455,
  },
  {
     category: "electronics",
     items: "laptop",
     price: 999,
  },
  {
     category: "beauty",
     items: "lipstick",
     price: 888,
  },
];
function compare( a, b ) {
  if ( a.category < b.category ){
    return 1;
  }
  if ( a.category > b.category ){
    return -1;
  }
  return 0;
}

console.log(data.sort( compare ));

Here i am filtering by every category and then pushing it to a new array in order to get the result i want.

CodePudding user response:

Because I'm an old-fashioned guy who loves tables...

const data = [{
    category: "sports",
    items: "shoes",
    price: 599,
  },
  {
    category: "electronics",
    items: "phones",
    price: 898,
  },
  {
    category: "sports",
    items: "shirt",
    price: 788,
  },
  {
    category: "sports",
    items: "ball",
    price: 455,
  },
  {
    category: "electronics",
    items: "laptop",
    price: 999,
  },
  {
    category: "beauty",
    items: "lipstick",
    price: 888,
  },
];

// group data by category
const grouped = data
  .reduce((c, { category, ...rest }) => {
    c[category] = c[category] || [];
    c[category].push({ ...rest });
    return c;
  }, {})

// write it to the table
// create the header
const thead = document.getElementById('header');
let row = document.createElement('tr');
Object.keys(data[0]).forEach(k => {
  let hdr = document.createElement('th');
  hdr.appendChild(document.createTextNode(k));
  row.appendChild(hdr);
});
thead.appendChild(row);

// now fill the body
const tbody = document.getElementById('products');
for (const [category, products] of Object.entries(grouped)) {
  let row = document.createElement('tr');
  let cat = document.createElement('td');
  cat.setAttribute('rowSpan', products.length);
  cat.appendChild(document.createTextNode(category));
  row.appendChild(cat);
  products.forEach(product => {
    Object.values(product).forEach(v => {
      let td = document.createElement('td');
      td.appendChild(document.createTextNode(v));
      row.appendChild(td);
    });
    tbody.appendChild(row);
    row = document.createElement('tr');
  });
}
td, th {
  padding: 5px;
}
<table border="1">
  <thead id="header"></thead>
  <tbody id="products">
  </tbody>
</table>

CodePudding user response:

  1. Group the data by its category using Array.prototype.reduce.

  2. And then loop over all the categories and for every category loop over all the items and create the desired markup.

const data = [
  { category: "sports", item: "shoes", price: 599 },
  { category: "electronics", item: "phones", price: 898 },
  { category: "sports", item: "shirt", price: 788 },
  { category: "sports", item: "ball", price: 455 },
  { category: "electronics", item: "laptop", price: 999 },
  { category: "beauty", item: "lipstick", price: 888 },
];

const categories = data.reduce(
  (r, o) => ((r[o.category] ??= []).push(o), r),
  {}
);

Object.keys(categories).forEach((cat) => {
  const section = document.createElement("section");
  const heading = document.createElement("h2");
  heading.textContent = cat;
  section.appendChild(heading);

  categories[cat].forEach((item) => {
    const div = document.createElement("div");
    const itemPara = document.createElement("p");
    itemPara.textContent = item.item;
    const pricePara = document.createElement("p");
    pricePara.textContent = item.price;
    div.appendChild(itemPara);
    div.appendChild(pricePara);
    section.appendChild(div);
  });

  document.body.appendChild(section);
});
section {
  border: 1px solid #ccc;
  border-radius: 0.25rem;
  padding: 1rem;
  text-transform: capitalize;
}

section   section {
  margin-top: 1rem;
}

section h2 {
  margin: 0.5rem 0;
}

section div {
  display: flex;
  justify-content: space-between;
}

section div p {
  margin: 0.25rem 0;
}

Relevant documentations:

  • Related