Skip to content

how to dynamically calculate row span for the given array of objects to display table

the JSON data which I get from service has different key-value pair. below is the example data which I need to convert the data in a table in the frontend and the first column and second column values are rowspan. is it possible to get rowspan dynamically based on records?

the data I have

const data = {
  header: [
    { value: 'DPM', label: 'DPM' },
    { value: 'Tracking Block', label: 'Tracking Block' },
    { value: 'Assessment', label: 'Assessment' },
    { value: 'POS', label: 'POS' },
    { value: 'Online', label: 'Online' },
    { value: 'Call Centre', label: 'Call Centre' },
  ],
  datasets: [
    {category: "Financing", subCategory: 'Capabilities', id: 'F.1', field: 'Channel availability', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Capabilities', id: 'F.2', field: '3rd party financing', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Capabilities', id: 'F.3', field: 'Finance Partner', pos: 'Text', online: 'Text', call: 'Text' },
    {category: "Financing", subCategory: 'Awareness', id: 'F.8', field: '‘Monthly price’ Visibility', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Awareness', id: 'F.9', field: '0% IFC', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Awareness', id: 'F.10', field: '', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Customer Experience', id: 'F.11', field: 'Digital e2e journey', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Customer Experience', id: 'F.16', field: 'Process duration', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Staff Advocacy', id: 'F.17', field: 'Commission incentive?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Staff Advocacy', id: 'F.18', field: 'Part of Training?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Staff Advocacy', id: 'F.19', field: 'Individual targets?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Capabilities', id: 'STI.1', field: 'Channel availability', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Capabilities', id: 'STI.5', field: 'RV Period', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Capabilities', id: 'STI.6', field: 'Competitive RV (vs. ARS)', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Capabilities', id: 'STI.7', field: 'RV top-up?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Capabilities', id: 'STI.8', field: 'LoB availability', pos: 'Multi select dropdown', online: 'Multi select dropdown', call: 'Multi select dropdown' },
    {category: "Spot Trade In", subCategory: 'Awareness', id: 'STI.9', field: 'Spot mechanism & Benefits', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Awareness', id: 'STI.12', field: 'CRM campaigns', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Customer Experience', id: 'STI.13', field: 'Buy-flow integration', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Customer Experience', id: 'STI.14', field: 'Omni-channel journey', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Customer Experience', id: 'STI.15', field: 'Device Grading (# questions)', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Staff Advocacy', id: 'STI.16', field: 'Commission incentive?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Staff Advocacy', id: 'STI.17', field: 'Part of Training?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    ]
}

the code

const App = () => {
  return (
    <div className="container-fluid p-2">
      <div className="table-responsive border border-secondary">
        <h4 className="text-center">Account+country</h4>
        <table className="table table-hover table-sm">
          <thead className="table-bordered">
            <tr>
              {data.header.map(element => {
                return (
                  <th scope="col" key={element.value} colSpan={element.colSpan}>
                    <div className="d-flex flex-column">
                      <div className="p-2 bd-highlight">{element.label}<span className="text-danger">*</span></div>
                    </div>
                  </th>
                )
              })}
            </tr>
          </thead>
          <tbody>
            {data.datasets.map(item => {
              return (
                <tr key={item.id}>
                  <td>{item.category}</td>
                  <td>{item.subCategory}</td>
                  <td>{item.field}</td>
                  <td>{item.pos}</td>
                  <td>{item.online}</td>
                  <td>{item.call}</td>
                </tr>
              )
            })}
          </tbody>
        </table>
      </div>
    </div>
  )
}

export default App

my output image enter image description here

expected output enter image description here

Answer

You just have to manipulate the array first, something like this:

const datasets: =  [
    { account:{title: 'India', rowSpan: 23},category: {title: "Financing", rowSpan: 11}, subCategory: 'Capabilities', id: 'F.1', field: 'Channel availability', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Financing", rowSpan: 0}, subCategory: 'Capabilities', id: 'F.2', field: '3rd party financing', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Financing", rowSpan: 0}, subCategory: 'Capabilities', id: 'F.3', field: 'Finance Partner', pos: 'Text', online: 'Text', call: 'Text' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Financing", rowSpan: 0}, subCategory: 'Awareness', id: 'F.8', field: '‘Monthly price’ Visibility', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Financing", rowSpan: 0}, subCategory: 'Awareness', id: 'F.9', field: '0% IFC', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Financing", rowSpan: 0}, subCategory: 'Awareness', id: 'F.10', field: '', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Financing", rowSpan: 0}, subCategory: 'Customer Experience', id: 'F.11', field: 'Digital e2e journey', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Financing", rowSpan: 0}, subCategory: 'Customer Experience', id: 'F.16', field: 'Process duration', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Financing", rowSpan: 0}, subCategory: 'Staff Advocacy', id: 'F.17', field: 'Commission incentive?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Financing", rowSpan: 0}, subCategory: 'Staff Advocacy', id: 'F.18', field: 'Part of Training?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Financing", rowSpan: 0}, subCategory: 'Staff Advocacy', id: 'F.19', field: 'Individual targets?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Spot Trade In", rowSpan: 12}, subCategory: 'Capabilities', id: 'STI.1', field: 'Channel availability', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Spot Trade In", rowSpan: 0}, subCategory: 'Capabilities', id: 'STI.5', field: 'RV Period', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Spot Trade In", rowSpan: 0}, subCategory: 'Capabilities', id: 'STI.6', field: 'Competitive RV (vs. ARS)', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Spot Trade In", rowSpan: 0}, subCategory: 'Capabilities', id: 'STI.7', field: 'RV top-up?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Spot Trade In", rowSpan: 0}, subCategory: 'Capabilities', id: 'STI.8', field: 'LoB availability', pos: 'Multi select dropdown', online: 'Multi select dropdown', call: 'Multi select dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Spot Trade In", rowSpan: 0}, subCategory: 'Awareness', id: 'STI.9', field: 'Spot mechanism & Benefits', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Spot Trade In", rowSpan: 0}, subCategory: 'Awareness', id: 'STI.12', field: 'CRM campaigns', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Spot Trade In", rowSpan: 0}, subCategory: 'Customer Experience', id: 'STI.13', field: 'Buy-flow integration', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Spot Trade In", rowSpan: 0}, subCategory: 'Customer Experience', id: 'STI.14', field: 'Omni-channel journey', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Spot Trade In", rowSpan: 0}, subCategory: 'Customer Experience', id: 'STI.15', field: 'Device Grading (# questions)', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Spot Trade In", rowSpan: 0}, subCategory: 'Staff Advocacy', id: 'STI.16', field: 'Commission incentive?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    { account:{title: 'India', rowSpan: 0},category: {title: "Spot Trade In", rowSpan: 0}, subCategory: 'Staff Advocacy', id: 'STI.17', field: 'Part of Training?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
];

To update the array:

const datasets =  [
    {category: "Financing", subCategory: 'Capabilities', id: 'F.1', field: 'Channel availability', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Capabilities', id: 'F.2', field: '3rd party financing', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Capabilities', id: 'F.3', field: 'Finance Partner', pos: 'Text', online: 'Text', call: 'Text' },
    {category: "Financing", subCategory: 'Awareness', id: 'F.8', field: '‘Monthly price’ Visibility', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Awareness', id: 'F.9', field: '0% IFC', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Awareness', id: 'F.10', field: '', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Customer Experience', id: 'F.11', field: 'Digital e2e journey', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Customer Experience', id: 'F.16', field: 'Process duration', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Staff Advocacy', id: 'F.17', field: 'Commission incentive?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Staff Advocacy', id: 'F.18', field: 'Part of Training?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Financing", subCategory: 'Staff Advocacy', id: 'F.19', field: 'Individual targets?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Capabilities', id: 'STI.1', field: 'Channel availability', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Capabilities', id: 'STI.5', field: 'RV Period', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Capabilities', id: 'STI.6', field: 'Competitive RV (vs. ARS)', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Capabilities', id: 'STI.7', field: 'RV top-up?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Capabilities', id: 'STI.8', field: 'LoB availability', pos: 'Multi select dropdown', online: 'Multi select dropdown', call: 'Multi select dropdown' },
    {category: "Spot Trade In", subCategory: 'Awareness', id: 'STI.9', field: 'Spot mechanism & Benefits', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Awareness', id: 'STI.12', field: 'CRM campaigns', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Customer Experience', id: 'STI.13', field: 'Buy-flow integration', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Customer Experience', id: 'STI.14', field: 'Omni-channel journey', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Customer Experience', id: 'STI.15', field: 'Device Grading (# questions)', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Staff Advocacy', id: 'STI.16', field: 'Commission incentive?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
    {category: "Spot Trade In", subCategory: 'Staff Advocacy', id: 'STI.17', field: 'Part of Training?', pos: 'Dropdown', online: 'Dropdown', call: 'Dropdown' },
];
    
    
    
const newDataSets = [];
datasets.forEach((data) => {
    newDataSets.push({...data, category: {title: data.category, rowSpan: 0}, subCategory: {title: data.subCategory, rowSpan: 0}})
})

const countCategories = datasets.reduce( (acc, o) => (acc[o.category] = (acc[o.category] || 0)+1, acc), {} );

const distinctCategories = [];

Object.keys(countCategories).forEach((data) => {
    distinctCategories.push({title: newDataSets[newDataSets.findIndex(x => x.category.title === data)].category.title, subCategories: newDataSets.filter(x => x.category.title === data)});
    (newDataSets[newDataSets.findIndex(x => x.category.title === data)]).category.rowSpan = countCategories[data]
})

distinctCategories.forEach((data) => {
    let countSubCategories = data.subCategories.reduce( (acc, o) => (acc[o.subCategory.title] = (acc[o.subCategory.title] || 0)+1, acc), {} );

    Object.keys(countSubCategories).forEach((subKey) => {
        let subId = (data.subCategories.find(x => x.subCategory.title === subKey)).id;
        newDataSets[newDataSets.findIndex(x => x.id === subId)].subCategory.rowSpan = countSubCategories[subKey]
    })
})

console.log(newDataSets)

then on your jsx part,

<tbody>
{newDataSets.map(item => {
    return (
    <tr key={item.id}>
        {item.category.rowSpan ? (
            <td rowspan={item.category.rowSpan}>{item.category.title}</td>
        ) : ''}
        {item.subCategory.rowSpan ? (
            <td rowspan={item.subCategory.rowSpan}>{item.subCategory.title}</td>
        ) : ''}
        <td>{item.field}</td>
        <td>{item.pos}</td>
        <td>{item.online}</td>
        <td>{item.call}</td>
    </tr>
    )
})}
</tbody>