Using CSS to design a table-like structure with rows that span multiple columns

I am trying to generate a table dynamically using CSS and a JSON array.

For example: In the code snippet provided, I have assigned a class of 'spannedrow' to span certain cells in the table, although the class is not defined yet. This is just for demonstration purposes. I require assistance in creating such a class.

var div="<div>";
    for(var i=0;i<myArr.length;i++) {     
        var arrHobies = myArr[i]['Hobbies'];
        var arrSkills = myArr[i]['Skills'];
        var arrLanguage = myArr[i]['Language'];
         div+="<div>";
         div+="<div class='spannedrow'>"+myArr[i]['Id']+"</td>";
         div+="<div class='spannedrow'>"+myArr[i]['Name']+"</td>";
         div+="<div class='spannedrow'>"+myArr[i]['Age']+"</td>";
         for(var j=0;j<arrHobies.length;j++ ) {
              div+="<div class='singlerow'>"+arrHobies[j]['HobbyId']+"</td>";
              div+="<div class='singlerow'>"+arrHobies[j]['HobbyName']+"</td>";
         }
          for(var l=0;l<arrSkills.length;l++ ) {
              div+="<div class='singlerow'>"+arrSkills[l]['SkillId']+"</td>";
              div+="<div class='singlerow'>"+arrSkills[l]['SkillName']+"</td>";
         }
         var div+="</div>"
    }
    var div+="</div>" ;  

Here is an example of my JSON array:

var myArr = [{
    "Id": 1,
    "Name": 'Ken',
    "Age": '30',
    "Hobbies": [{
      'HobbyId': 1,
      'HobbyName': 'Swimming'
    }, {
      'HobbyId': 2,
      'HobbyName': 'Reading'
    }],
    "Skills": [{
      'SkillId': 1,
      'SkillName': 'PHP'
    }, {
      'SkillId': 2,
      'SkillName': 'MySQL'
    }],
    "Language": [{
      'LangId': 2,
      'LangName': 'English'
    }, {
      'LangId': 3,
      'LangName': 'Chinese'
    }]
  },
  {
    "Id": 2,
    "Name": 'Mike',
    "Age": '20',
    "Hobbies": [],
    "Skills": [],
    "Language": []
  },
  {
    "Id": 3,
    "Name": 'Charlie',
    "Age": '25',
    "Hobbies": [{
      'HobbyId': 5,
      'HobbyName': 'Dance'
    }, {
      'HobbyId': 6,
      'HobbyName': 'Sing'
    }, {
      'HobbyId': 7,
      'HobbyName': 'Writing'
    }],
    "Skills": [],
    "Language": [{
      'Id': 7,
      'Name': 'English'
    }]
  }
]

The table representation of this array can be seen here.

Would it be possible to achieve row spanning with CSS styles?

I am now incorporating actual dynamic data into the mix.

 var myArr = [
            {
                "ItemMasterNumber":"290015","IM_Description":"XXX5","IM_FirstProcessDate":"10-19-2016",
                "IM_Alias":"test"                
                "ItemFeatureSet":
                        [{"FS_Id":"2002","FS_Code":"XXX5","FS_Name":"XXX5","FS_Description":"XXX5"}],
                "ItemFeatures":
                      [{"FE_Id":"1864","FE_Value":"VERSION","FE_Name":"2017"},
                       {"FE_Id":"1865","FE_Value":"EDITION","FE_Name":"Deluxe"}],
                "ItemCharges":[
                    {"CH_ChargeId":"23004746","CH_Name":"XXX5","CH_Description":"",
                        "CH_Type":"One Time"
                     }],
                "ItemChargeAttributes":[
                         {"CA_Id":"1628","CA_ListPrice":"99","CA_FairValueBasis":"BESP"}],
                "ItemPackages":[{"PA_PackageId":"21004482"}],
                "ItemPackagesComponents":[{"PA_Id":"9189","PA_Type":"Feature Set"},{"PA_Id":"9190","PA_Type":"Charge"}],
                "ItemOffers":[{"OF_OfferId":"20003880","OF_Name":"XXX5"}],
                "ItemOffersComponents":[{"OC_Id":"3877","OC_Quantity":"","OC_AdjustmentAmount":""}]
            }];

After attempting to use the above real array, some data mixing issues were encountered with the following code:

<html>
  <head>
    <title>TODO supply an appropriate title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script>
        $( document ).ready(function() {
        var myArr = [
            {
                "ItemMasterNumber":"290015","IM_Description":"XXX5","IM_FirstProcessDate":"10-19-2016",
                "IM_Alias":"test"                
                "ItemFeatureSet":
                        [{"FS_Id":"2002","FS_Code":"XXX5","FS_Name":"XXX5","FS_Description":"XXX5"}],
                "ItemFeatures":
                      [{"FE_Id":"1864","FE_Value":"VERSION","FE_Name":"2017"},
                       {"FE_Id":"1865","FE_Value":"EDITION","FE_Name":"Deluxe"}],
                "ItemCharges":[
                    {"CH_ChargeId":"23004746","CH_Name":"XXX5","CH_Description":"",
                        "CH_Type":"One Time"
                     }],
                "ItemChargeAttributes":[
                         {"CA_Id":"1628","CA_ListPrice":"99","CA_FairValueBasis":"BESP"}],
                "ItemPackages":[{"PA_PackageId":"21004482"}],
                "ItemPackagesComponents":[{"PA_Id":"9189","PA_Type":"Feature Set"},{"PA_Id":"9190","PA_Type":"Charge"}],
                "ItemOffers":[{"OF_OfferId":"20003880","OF_Name":"XXX5"}],
                "ItemOffersComponents":[{"OC_Id":"3877","OC_Quantity":"","OC_AdjustmentAmount":""}]
            }];
console.log(JSON.stringify(myArr));
// Assuming it's not going to be empty
var headers = ["Item Number", "Description", "First Process Date", "Alias", "Master Price", "Product Id", "Product Description",
    "FeatureSet #","Feature Set Code","Name","Description","Enablement Type",
    "Feature Id","Value","Name",
    "Charge Id","Name","Description","Type",
     "Record Id","List Price","Fair Value Basis","Fair Value Low","Fair Value High","Effective SD",
    "Package Id",
    "Record Id","Component Type",
    "Offer Id","Name","Description","Type","Level","Effective SD",
    "Record Id","Quantity","Adjustment Amt"

    ];

var containers = ["ItemFeatureSet", "ItemFeatures", "ItemCharges",
    "ItemChargeAttributes",
    "ItemPackages","ItemPackagesComponents","ItemOffers",
    "ItemOffersComponents"];

for (let header of headers)
{
    console.log('Ok');
    console.log('${header}')
  $("#headers").append(`<th>${header}</th>`);
}

// foreach item
for (let group of myArr)
{
  let span = 1;

  // Sets the length of row span
  for (let container of containers)
  {
    span = group[container].length > span ? group[container].length : span;
  }

  // for the first/main row of each item
  let temp_tr = $("<tr>");
  for (let item in group)
  {
    // Checking if key is array
    if (Array.isArray(group[item]))
    {
      let insert_value = "";
      //If it is greater than 0 use value
      if (group[item].length)
      {
        let temp_keys = Object.keys(group[item][0]);
        for (let tk of temp_keys)
        {
          insert_value += `<td>${group[item][0][tk]}</td>`;
        }
      }
      else
      {
        insert_value += "<td></td><td></td>";
      }

      $(temp_tr).append(insert_value);
    }
    else
    {
      $(temp_tr).append(`<td rowspan=${span}>${group[item]}</td>`);
    }

  }
  // Add to tbody
  $("#body").append(temp_tr); 


  // for each inner item
  for (let i = 1; i < span; i++)
  {
    let temp_tr = $("<tr>");

    for (let item of containers)
    {
      let insert_value = "";

      // Only add values if there are any
      if (i < group[item].length)
      {
        let temp_keys = Object.keys(group[item][i]);
        for (let tk of temp_keys)
        {
          insert_value += `<td>${group[item][i][tk]}</td>`;
        }
      }
      else
      {
        insert_value += "<td></td><td></td>";
      }
      $(temp_tr).append(insert_value);  
      $("#body").append(temp_tr);
    }

  }


}
 });
    </script>
  </head>
  <body>
      <table id="mytable" border=1>
  <thead>
    <tr>
      <th colspan=7></th>
      <th colspan=5>Feature Set Related Data</th>
      <th colspan=3>Features Related Data</th>
      <th colspan=4>Charges Related Data</th>
      <th colspan=6>Charge Attribute Related Data</th>
      <th colspan=1>Package Related Info</th>
      <th colspan=2>Package Component Related Data</th>
      <th colspan=6>Offer Related Data</th>
      <th colspan=3>Offers Component Related Data</th>
    </tr>
    <tr id="headers">
    </tr>
  </thead>
  <tbody id="body">
  </tbody>
</table>
  </body>
</html>

Answer №1

If you need any clarification, feel free to ask about my answer. It might be lacking some validation somewhere, but I believe it's a solid starting point. Experiment with the border CSS properties to achieve your desired look.

var myArr = [{
    "Id": 1,
    "Name": 'Ken',
    "Age": '30',
    "Hobbies": [{
      'HobbyId': 1,
      'HobbyName': 'Swimming'
    }, {
      'HobbyId': 2,
      'HobbyName': 'Reading'
    }],
    "Skills": [{
      'SkillId': 1,
      'SkillName': 'PHP'
    }, {
      'SkillId': 2,
      'SkillName': 'MySQL'
    }],
    "Language": [{
      'LangId': 2,
      'LangName': 'English'
    }, {
      'LangId': 3,
      'LangName': 'Chinese'
    }]
  },
  {
    "Id": 2,
    "Name": 'Mike',
    "Age": '20',
    "Hobbies": [],
    "Skills": [],
    "Language": []
  },
  {
    "Id": 3,
    "Name": 'Charlie',
    "Age": '25',
    "Hobbies": [{
      'HobbyId': 5,
      'HobbyName': 'Dance'
    }, {
      'HobbyId': 6,
      'HobbyName': 'Sing'
    }, {
      'HobbyId': 7,
      'HobbyName': 'Writing'
    }],
    "Skills": [],
    "Language": [{
      'Id': 7,
      'Name': 'English'
    }]
  }
];

// Assuming it's not going to be empty
var headers = ["Id", "Name", "Age", "HobbyId", "HobbyName", "SkillId", "SkillName", "Id", "Name"];

var containers = ["Hobbies", "Skills", "Language"];

for (let header of headers)
{
  $("#headers").append(`<th>${header}</th>`);
}

// foreach item
for (let group of myArr)
{
  let span = 1;
  
  // Sets the length of row span
  for (let container of containers)
  {
    span = group[container].length > span ? group[container].length : span;
  }
  
  // for the first/main row of each item
  let temp_tr = $("<tr>");
  for (let item in group)
  {
    // Checking if key is array
    if (Array.isArray(group[item]))
    {
      let insert_value = "";
      //If it is greater than 0 use value
      if (group[item].length)
      {
        let temp_keys = Object.keys(group[item][0]);
        for (let tk of temp_keys)
        {
          insert_value += `<td>${group[item][0][tk]}</td>`;
        }
      }
      else
      {
        insert_value += "<td></td><td></td>";
      }
      
      $(temp_tr).append(insert_value);
    }
    else
    {
      $(temp_tr).append(`<td rowspan=${span}>${group[item]}</td>`);
    }

  }
  // Add to tbody
  $("#body").append(temp_tr); 
  
  
  // for each inner item
  for (let i = 1; i < span; i++)
  {
    let temp_tr = $("<tr>");
    
    for (let item of containers)
    {
      let insert_value = "";

      // Only add values if there are any
      if (i < group[item].length)
      {
        let temp_keys = Object.keys(group[item][i]);
        for (let tk of temp_keys)
        {
          insert_value += `<td>${group[item][i][tk]}</td>`;
        }
      }
      else
      {
        insert_value += "<td></td><td></td>";
      }
      $(temp_tr).append(insert_value);  
      $("#body").append(temp_tr);
    }
    
  }

  
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="mytable" border=1>
  <thead>
    <tr>
      <th colspan=3></th>
      <th colspan=2>Hobbies</th>
      <th colspan=2>Skills</th>
      <th colspan=2>Language</th>
    </tr>
    <tr id="headers">
    </tr>
  </thead>
  <tbody id="body">
  </tbody>
</table>

Answer №2

If you want to create a table layout, consider this structure:

var dataArr = [{
    "ID": 1,
    "Name": 'Ken',
    "Age": '30',
    "Interests": [{
      'InterestID': 1,
      'InterestName': 'Swimming'
    }, {
      'InterestID': 2,
      'InterestName': 'Reading'
    }],
    "Skills": [{
      'SkillID': 1,
      'SkillName': 'PHP'
    }, {
      'SkillID': 2,
      'SkillName': 'MySQL'
    }],
    "Language": [{
      'LangID': 2,
      'LangName': 'English'
    }, {
      'LangID': 3,
      'LangName': 'Chinese'
    }]
  },
  {
    "ID": 2,
    "Name": 'Mike',
    "Age": '20',
    "Interests": [],
    "Skills": [],
    "Language": []
  },
  {
    "ID": 3,
    "Name": 'Charlie',
    "Age": '25',
    "Interests": [{
      'InterestID': 5,
      'InterestName': 'Dance'
    }, {
      'InterestID': 6,
      'InterestName': 'Sing'
    }, {
      'InterestID': 7,
      'InterestName': 'Writing'
    }],
    "Skills": [],
    "Language": [{
      'LangID': 7,
      'LangName': 'English'
    }]
  }
];

function generateRows(object, maxRow, id, name) {
  var tableContent = '';
  if (object.length || maxRow) {
      tableContent += "<table>";
      object.length && $(object).each(function() {
          tableContent += '<tr><td width="40%">' + this[id] + '</td><td width="60%">' + this[name] + '</td></tr>';
      });
      if (object.length<maxRow){
        for(var i=0,l=maxRow-object.length;i<l;i++){
          tableContent += '<tr><td width="40%">&nbsp;</td><td  width="60%">&nbsp;</td></tr>';
        }
      }
      tableContent += '</table>';
    }
    return tableContent;
}

var tableContent = "<table border='1' style='border:1px solid #000;' cellpadding='0' cellspacing='0' >";
tableContent += '<tr><td colspan="3"></td>' +
  '<td>Interests</td><td>Skills</td><td>Languages</td></tr>';
tableContent += '<tr><td>ID</td><td>Name</td><td>Age</td>' +
  '<td><table><tr><td width="40%">Interest ID</td><td  width="60%">Interest Name</td></tr></table>'+
  '<td><table><tr><td width="40%">Skill ID</td><td  width="60%">Skill Name</td></tr></table>'+
  '<td><table><tr><td width="40%">Language Id</td><td  width="60%">Language Name</td></tr></table>';
for (var i = 0; i < myArr.length; i++) {
  var interestsArray = myArr[i]['Interests'];
  var skillsArray = myArr[i]['Skills'];
  var languageArray = myArr[i]['Language'];
  var maximumRows=Math.max(interestsArray.length,skillsArray.length,languageArray.length);
  tableContent += "<tr>";
  tableContent += "<td valign='top' class='pad-5'>" + myArr[i]['ID'] + "</td>";
  tableContent += "<td valign='top' class='pad-5'>" + myArr[i]['Name'] + "</td>";
  tableContent += "<td valign='top' class='pad-5'>" + myArr[i]['Age'] + "</td>";
  tableContent += '<td>'+
          generateRows(interestsArray,maximumRows,'InterestID','InterestName')+
          '</td>';
  tableContent += '<td>'+
          generateRows(skillsArray,maximumRows,'SkillID','SkillName')+
          '</td>';
  tableContent += '<td>'+
          generateRows(languageArray,maximumRows,'LangID','LangName')+
          '</td>'; 
  tableContent += "</tr>"
}
tableContent += "</table>";
$(tableContent).appendTo('body');
table {
  border-collapse:collapse;
  width:100%;
}
table table td {
  border: 1px solid black;
  padding:5px;

}
.pad-5{padding:5px}
table table tr:first-child td {
  border-top: 0;
}
table table tr:last-child td {
  border-bottom: 0;
}
table table tr td:first-child {
  border-left: 0;
}
table table tr td:last-child{
  border-right: 0;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

This updated content reflects handling dynamic information:

var dataArr = [` Updated data array goes here `];
var newTable = '<table border="1"><tr>';
        tblData=[],
        isFirstRow = true;

        for (var i = 0, cols = Object.keys(dataArr[0]), l = cols.length; i < l; i++) {
            newTable += '<th>' + cols[i] + '</th>';
        };
        newTable += '</tr>';

        tblData.push(newTable);
        $.each(dataArr, function(index, obj) {
            newTable = '<tr>';

            $.each(obj, function(key, value) {
                isFirstRow = !index;
                if ($.isArray(value)) {
                    if (isFirstRow) {
                        newTable += '<td><table><tr>';

                        for (var i = 0, cols = Object.keys(value[0]), l = cols.length; i < l; i++) {
                            newTable += '<th>' + cols[i] + '</th>';
                        }
                        newTable += '</tr>';
                        isFirstRow=false;
                    } else {
                        newTable += '<td><table>';
                    }               
                    $.each(value, function(k, val) {
                        newTable += '<tr>';
                        $.each(val, function(j, v) {
                            newTable += '<td> ' + v + ' </td>';
                        });
                        newTable += '</tr>';
                    });
                    newTable += '</table></td>';
                } else {
                    value = value.trim().length==0 ? '&nbsp;':value;
                    newTable += '<td> ' + value + ' </td>';
                }


            });
            isFirstRow = false;
            newTable += '</tr>';
            tblData.push(newTable);
        });

        $(tblData.join()).appendTo('body');

        $('table th').each(function(){
            $(this).text(function(){
                return $(this).text().replace(/([A-Z])/g, ' $1').replace('_',' ')
                .replace(/^./, function(str){ return str.toUpperCase(); })
        });
    });
table {
  border-collapse: collapse;
  width: 100%;
}

table table td,
table table th {
  border: 1px solid black;
}

.pad-5 {
  padding: 5px
}

table table tr:first-child td,
table table tr:first-child th {
  border-top: 0;
}

table table tr:last-child td,
table table tr:last-child th {
  border-bottom: 0;
}

table table tr td:first-child,
table table tr th:first-child {
  border-left: 0;
}

table table tr td:last-child,
table table tr th:last-child {
  border-right: 0;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

minimize the size of the image within a popup window

I encountered an issue with the react-popup component I am using. When I add an image to the popup, it stretches to full width and length. How can I resize the image? export default () => ( <Popup trigger={<Button className="button" ...

I'm currently attempting to incorporate the Material-UI InfoIcon into my code, but I'm unsure of how to properly integrate it within a TextField component

I am attempting to integrate the Material-UI InfoIcon into my TextField code, but I'm unsure of how to go about it. Here is the snippet of Material-UI code: <InfoIcon fontSize="small" /> This is where I would like to place it: <Grid item ...

Embedded Youtube code saved in database is not displaying on HTML form

My PHP update page allows me to modify a website's database that contains YouTube embed codes. However, when I try to edit the embed code on the update page, only "<iframe width=" displays instead of the complete original code. <html> <? ...

Capture latitude and longitude using HTML5 Geolocation and store the values in a PHP variable

In the midst of a project, I am tasked with obtaining the longitude and latitude of a user in order to pinpoint their location. The challenge lies in storing this data in PHP variables, which will ultimately be saved in a MySQL database. Can anyone offer ...

The functionality of the jQuery scroll feature appears to be malfunctioning

I am trying to implement a scroll event and have written the following code: <script type="text/javascript> $(function () { $(window).scroll(function () { alert($("body").scrollTop()); }); }); ...

An error occurred: TypeError - Unable to access the 'value' property of a null object during a value change

Example ImageCreating a dynamic form where rows and select box options are added dynamically using 'x' and 'i' increment values in two JavaScript functions. The code works fine when the option selected is 0.5, but throws an error Uncaug ...

Struggling to set the value for a variable within an Angular factory?

When dealing with a variable as an array, I have no trouble pushing objects inside and retrieving the values within the controller. However, when trying to directly assign an object to that variable, I run into issues. If anyone can assist me in achieving ...

Variations in the appearance of scrollbars on the x-axis and y-axis within a single <div> element

Let's say we have a div element like this: <div class="nav-menu"></div> I want to customize the CSS style for scrollbar using the ::scrollbar pseudo-element: .nav-menu::-webkit-scrollbar { width: 8px; background: white; ...

Why is Handlebars {{body}} not rendering my HTML tags properly?

I am perplexed by the fact that the example in the other file is not showing. While working on a CRUD project with Mongo, Express, and Node, I encountered an issue. The code wasn't functioning as expected, so I paused to figure out why. <!DOCTYPE ...

What is the best way to change a date from the format DD/MM/YYYY to YYYY-MM-DD

Is there a way to use regular expressions (regex) to convert a date string from DD/MM/YYYY format to YYYY-MM-DD format? ...

The JavaScript audio is not working for the first three clicks, but starts playing smoothly from the fourth click onwards. What could be causing this issue?

$(".btn").click(function(event){ playSound(event.target.id); }); function playSound(name){ $("." + name).click(function() { new Audio("sounds/" + name + ".mp3").play(); ...

Ensuring draggable div remains fixed while scrolling through the page

I am currently working on creating a draggable menu for my website. The menu is functional and can be moved around the page as intended. However, I have encountered an issue where the menu disappears when scrolling down the page due to its position attrib ...

Utilizing JSON API filtering within a Next.js application

Recently delving into the world of coding, I've embarked on a personal project that has presented me with a bit of a challenge regarding API filtering. My goal is to render data only if it contains a specific word, like "known_for_department==Directin ...

Having issues with inline conditional statements in Angular 5

There is a minor issue that I've been struggling to understand... so In my code, I have an inline if statement like this: <button *ngIf="item?.fields?.assetType !== 'tool' || item?.fields?.assetType !== 'questions'">NEXT< ...

What is the best way to add a property and its value to objects within an array, especially those which do not currently have that specific property?

My goal is to: Iterate through the peopleData array, add a property named 'age' and assign it a value of '-' for any objects in the array that do not have the key 'age' const peopleData = [ { name: "Ann", age: 15, email: ...

jQuery UI dynamically adjusting content layout based on browser size changes

Having an issue with my custom accordion script where resizing the browser causes formatting problems in one of the sections. I want the content to remain intact and to utilize a scrollbar if necessary to view the content. The problem is visible in section ...

How can I send data in JSON format to a JavaScript AJAX request?

I've created a method that looks like this: public String getUTResult() throws IOException { BuildResultParser bp = new BuildResultParser(); BuildResultBean b = bp.getreadFile("C:\\bc.txt"); String str = b.getuTresult(); ...

What is the reason behind the change in size and shape of the text when using "overflow: hidden"?

Check out this interactive demo using the provided HTML and CSS: You can view the demo by clicking on this link. /*CSS*/ .header { margin: 0px; padding: 0px; width: 100%; } .headertable { padding: 0px; margin: 0px; width: 100%; border-sp ...

Customize the font color in Material UI to make it uniquely yours

How can I customize the default Text Color in my Material UI Theme? Using primary, secondary, and error settings are effective const styles = { a: 'red', b: 'green', ... }; createMuiTheme({ palette: { primary: { ...

Troubleshooting Tips for Resolving Problems with VueJS getElementById Bug

I'm currently working with a VueJS single File component that has the following template: <template> <div class="row"> <div class="col-md-12"> <div id="hottable"></div> < ...