Search code examples
javascriptreactjsreact-bootstrap

Dynamically add item into react-bootsrap accordion


I'm getting my data from database. Then I would like them to be categorized by "item_category" and have them in react-bootstrap accordion.

So far I have this:

<Accordion>
            {
                items.map((item, index) => {
                    if(item.item_category === "Submachines"){
                        return (
                            <Accordion.Item eventKey={index} key={index}>
                                <Accordion.Header>{item.item_category}</Accordion.Header>
                                <Accordion.Body>
                                    <Item key={index} 
                                    itemName={item.item_name} 
                                    itemImageUrl={item.item_image} 
                                    itemCategory={item.item_category}
                                    sellPrice={item.sell_price}
                                    buyPrice={item.buy_price}
                                    slotSize={item.slot_size}
                                    />
                                </Accordion.Body>
                            </Accordion.Item>
                        );
                    }
                })  
            }
            
        </Accordion>

But It's kind of wrong as this is creating an accordion item for each item in items array. What I would like to have is for each category to have only one accordion item.

Can someone point me in right direction, please ? Thanks


Solution

  • You can either get items from backend already grouped by category or you can ask for category while iterating over your items, save them grouped by category and only then render Accordion.Item for each category:

    • Iterate over items
    • Create an object for categories
    • Look up if item.item_category exist as property in yur categories object
    • If no, first create property, then add item as value in a list
    • If yes, add item as value in a list
    • When you are done with iterating, iterate over your categories object and render an Accordion.Item for every property (=category).

    Example categories object:

    const categories = {
      "catA": [ item1, item2, item3],
      "catB": [ item4, item5, item6],
      "catC": [ item7, item8, item9]
    }
    

    Edit:

    Please look into following codesandbox: https://codesandbox.io/s/charming-mirzakhani-9n344i

     const categories = {};
      for (const item of items) {
        if (item.item_category in categories) {
          categories[item.item_category].push(item);
        } else {
          categories[item.item_category] = [item];
        }
      }
      return (
        <Accordion>
          {Object.entries(categories).map((entry) => {
            const category = entry[0];
            const itemList = entry[1];
            return (
              <Accordion.Item eventKey={category} key={category}>
                <Accordion.Header>{category}</Accordion.Header>
                <Accordion.Body>
                  {itemList.map((item) => (
                    <span>{item.name} </span>
                  ))}
                </Accordion.Body>
              </Accordion.Item>
            );
          })}
        </Accordion>
      );