Merge Objects under the same ID and display in HTML Table in JQuery

Viewed 65

UPDATE: I should have asked in a better way. My bad. but I struggle to find a way to display it inside a table. I did use reduce() method for this which i got the result by looking at the console log

I am actually stuck on something. As the title above tells you. I need helps on how to get the result for this.

Below is the code

let arr = [{
  reference: "A2",
  sendTo: "USA",
  item: "sticker",
  sku: 0921380,
  quantity: 1
},
{
  reference: "A2",
  sendTo: "USA",
  item: "toy",
  sku: 0921381,
  quantity: 2
}, {
  reference: "A2",
  item: "pencil",
  sku: 0921382,
  quantity: 2
},
 {
  reference: "A3",
  item: "sticker",
  sendTo: "USA",
  sku: 0921380,
  quantity: 2
}]

console.log(Array)

Javascript I use for this issue (credits to people here for this too):

let newArr = arr.reduce((acc, curr) => {
   if(acc.some(obj => obj.reference === curr.reference)) {
       acc.forEach(obj => {
          if(obj.reference === curr.reference) {
          obj.sku = obj.sku + ", " + curr.sku
          obj.quantity = obj.quantity + ", " + curr.quantity
       }
     });
    } else {
        acc.push(curr)
      }
      return acc
    }, [])

Result after merging:

reference: A2
sendTo: USA
item: sticker, toy, pencil
sku: 0921380, 0921381, 0921382
quantity: 1, 2 ,2

reference: A3
item: sticker
sendTo: USA
sku: 0921380
quantity: 2

However, I need to make it appear inside a HTML Table as below:

| reference | sendTo | item    | sku      | quantity |
|----------------------------------------------------|
| A2          USA      sticker   0921380    1        |
|                      toy       0921381    2        |
|                      pencil    0921382    2        |
|----------------------------------------------------|
| A3          USA      sticker   0921380    2        |
|----------------------------------------------------|
3 Answers

Use a reduce() for that.

let arr = [{
  reference: "A0002",
  sendTo: "USA",
  item: "sticker",
  sku: 0921380,
  quantity: 1
},
{
  reference: "A0002",
  sendTo: "USA",
  item: "toy",
  sku: 0921381,
  quantity: 2
}, {
  reference: "A0002",
  item: "pencil",
  sku: 0921382,
  quantity: 2
},
 {
  reference: "A0003",
  item: "sticker",
  sendTo: "USA",
  sku: 0921380,
  quantity: 2
}];

let result = arr.reduce((previousValue, currentValue) => {
     if (exists = previousValue.find(i => i.reference === currentValue.reference)) {
         exists.item += ', ' + currentValue.item;
         exists.sku += ', ' + currentValue.sku;
         exists.quantity += ', ' + currentValue.quantity;
     } else {
         previousValue.push(currentValue);
     }
     return previousValue;
}, []);

console.log(result);

Assuming the elements are already sorted:

const data = [{
  reference: "A0002",
  sendTo: "USA",
  item: "sticker",
  sku: 0921380,
  quantity: 1
},
{
  reference: "A0002",
  sendTo: "USA",
  item: "toy",
  sku: 0921381,
  quantity: 2
}, {
  reference: "A0002",
  item: "pencil",
  sku: 0921382,
  quantity: 2
},
 {
  reference: "A0003",
  item: "sticker",
  sendTo: "USA",
  sku: 0921380,
  quantity: 2
}]

const table = document.getElementById('myTable')
let sameCount = 0
for (let i = 0; i < data.length; i++) {
    const row = table.insertRow()
    let cell
    if (sameCount == 0) {
        for (let j = i + 1; j < data.length && data[j].reference == data[i].reference; j++)
            sameCount++
        cell = row.insertCell()
        cell.innerHTML = data[i].reference
        cell.setAttribute('rowspan', sameCount + 1)
        cell = row.insertCell()
        cell.innerHTML = data[i].sendTo
        cell.setAttribute('rowspan', sameCount + 1)
    } else {
        sameCount--
    }
    cell = row.insertCell()
    cell.innerHTML = data[i].item
    cell = row.insertCell()
    cell.innerHTML = data[i].sku
    cell = row.insertCell()
    cell.innerHTML = data[i].quantity
}
table, th, td {
  border: 1px solid;
}
<table id="myTable">
    <tr>
        <th>reference</th>
        <th>sendTo</th>
        <th>item</th>
        <th>sku</th>
        <th>quantity</th>
    <tr>
</table>

Outline

You actually do not need the aggregation in order to create the output. Instead, order the data array by the grouping properties ( reference, sendTo ) and iterate through the result, suppressing output of the group columns while their (tuple) value does not change.

Implementation

<html>
    <head>
        <title>SO _: Pivot table gen</title>
        <style type="text/css">
            table {
                border-collapse: collapse;
            }
            td, th {
                padding: 0.5em;
                border-left: solid 1px black;
                border-right: solid 1px black;
            }
            td.newGroup, th {
                border-top: solid 1px black;
            }
            tr:last-of-type > td, tr:last-of-type > th {
                border-bottom: solid 1px black;
            }
        </style>
        <script type="text/javascript">
            let arr = [{
              reference: "A0002",
              sendTo: "USA",
              item: "sticker",
              sku: 0921380,
              quantity: 1
            },
            {
              reference: "A0002",
              sendTo: "USA",
              item: "toy",
              sku: 0921381,
              quantity: 2
            }, {
              reference: "A0002",
              sendTo: "USA",
              item: "pencil",
              sku: 0921382,
              quantity: 2
            },
             {
              reference: "A0003",
              item: "sticker",
              sendTo: "USA",
              sku: 0921380,
              quantity: 2
            }];
            
            // in-situ sorting
            arr.sort ( (a, b) => {
                let n_cmp
                  ;
                  
                n_cmp =
                    (a.reference === b.reference)
                        ? Math.sign(a.sku - b.sku)
                        : a.reference.localeCompare(b.reference)
                ;
                return n_cmp;
            });

            
            let orderedColumns = [
                'reference'
              , 'sendTo'
              , 'item'
              , 'sku'
              , 'quantity'
            ];
                            
            console.log(JSON.stringify(arr));
        </script>
    </head>
    <body>
        <!--
            - 'orderedColumns' are the ... well :)
            - 'as_lastKeys' is the array of the currently active grouping key
            - 'b_sameKey' flags for each record that the grouping key has not changed.
            
            - CSS class 'newGroup' identifies the start of a new group and allows for CSS markup to visualize the grouping.
              Note that for convenience the same class is used for non-grouping columns.
              
            - The elements are generated on the fly by scripts.
              The alternative is to use the DOM API to add html elements with attributes.
              The control flow basically is the same, see maraca's answer for details (https://stackoverflow.com/a/72713958)
        -->
        <table>
            <thead>
                <tr>
                    <script>orderedColumns.forEach ( ps_key => { document.write(`<th>${ps_key}</th>`); } );</script>
                </tr>
            </thead>
            <tbody>
                <script>
                    let as_lastKeys = ['', ''];
                    
                    arr.forEach ( po_record => {
                        let b_sameKey = as_lastKeys.every ( (ps_value, pn_idxKey) => { return ps_value === po_record[orderedColumns[pn_idxKey]]; })
                          ;

                        document.write('<tr>');
                        orderedColumns.forEach ( (ps_key, pn_idxColumn) => {
                            if (pn_idxColumn < as_lastKeys.length) { // Key columns (text not repeated in table output)
                                if (b_sameKey) {
                                    document.write(`<td>&nbsp;</td>`);
                                } else {
                                    as_lastKeys[pn_idxColumn] = po_record[ps_key];
                                    document.write(`<td class="newGroup">${po_record[ps_key]}</td>`);
                                }
                            } else {
                                document.write(`<td class="newGroup">${po_record[ps_key]}</td>`);
                            }
                        });
                        document.write('</tr>');
                    });
                </script>
            </tbody>
        </table>
    </body>
</html>

Related