[英]Javascript Create complex table header from json
I want to create a html table header with colspan and i'm lost; 我想用colspan创建一个html表头,我迷路了; i have this json:
我有这个json:
var metadata = [{
"colIndex": 0,
"colType": "String",
"colName": "PM"
}, {
"colIndex": 1,
"colType": "String",
"colName": "PROD"
}, {
"colIndex": 2,
"colType": "Numeric",
"colName": "NR/M1"
}, {
"colIndex": 3,
"colType": "Numeric",
"colName": "NR/M2"
}, {
"colIndex": 4,
"colType": "Numeric",
"colName": "NR/M3"
}, {
"colIndex": 5,
"colType": "Numeric",
"colName": "NR/M4"
}, {
"colIndex": 6,
"colType": "Numeric",
"colName": "NR/M5"
}, {
"colIndex": 7,
"colType": "Numeric",
"colName": "NR ART/M6"
}, {
"colIndex": 8,
"colType": "Numeric",
"colName": "NR ART/M1"
}, {
"colIndex": 9,
"colType": "Numeric",
"colName": "NR ART/M2"
}, {
"colIndex": 10,
"colType": "Numeric",
"colName": "NR ART/M3"
}, {
"colIndex": 11,
"colType": "Numeric",
"colName": "NR ART/MX"
}];
The table header will be, mostly, based on spliting "colType": "Numeric" 该表头主要基于拆分“ colType”:“ Numeric”
+------+-------+-----+--------+-----+-----+-----+-----+------+----+----+----+
| | | NR | NR ART |
+ PAM | PROD +-----+--------+-----+-----+-----+-----+------+----+----+----+
| | M1 | M2 | M3 | M4 | M5 | M6 | M1 | M2 | M3 | MX |
+------+-------+-----+--------+-----+-----+-----+-----+------+----+----+----+
First i tried to split colName where colType is numeric 首先我尝试在colType为数字的情况下拆分colName
var arr = [], a;
$.each(metadata, function (i, v) {
arr.push(v.colName.split("/"));
a = v.colName.split("/").length;
});
next, i get unique parents (?), but what can i do with this? 接下来,我得到了唯一的父母(?),但是我该怎么办? i think i must travers this array in hierarchie (parent - children and then to construct the html header).
我认为我必须遍历此数组(父级-子级,然后构造html标头)。
The array is dynamic. 该数组是动态的。
Any advice? 有什么建议吗? Please and thank you.
谢谢,麻烦您了。
the below code should do the work please check 下面的代码应该做的工作,请检查
var arr = {}, a;
$.each(metadata, function (i, v) {
arr[v.colName.split("/")[0]] = arr[v.colName.split("/")[0]].push(v.colName.split("/")[1]) || [] ;
});
In order to display it 为了显示它
for(t1 in arr){
if(t1.length > 0){
//has children element
}
else{
//has only 1 element
}
}
One thing which complicates this, is the need for colspan
and rowspan
in your table. 使此问题复杂化的一件事是表中需要
colspan
和rowspan
。 So, you need to do a group count on your objects based on the colName property. 因此,您需要基于colName属性对对象进行组计数。
Here is a crude example of how you could do it. 这是如何实现的粗略示例。 Explanation is in the code comments.
说明在代码注释中。 (This example uses group count for
colspan
, but rowspan
is hard-coded. You can do a group-count for rowspan
as well). (此示例对
colspan
使用组计数,但对rowspan
进行硬编码。您也可以对rowspan
进行组计数)。
I have used jQuery in this example only for creating and adding the table. 在此示例中,我仅将jQuery用于创建和添加表。 The core logic is in plain Javascript .
核心逻辑使用纯Javascript 。
Snippet : 片段 :
var metadata = [{"colIndex": 0, "colType": "String", "colName": "PM"}, {"colIndex": 1, "colType": "String", "colName": "PROD"}, {"colIndex": 2, "colType": "Numeric", "colName": "NR/M1"}, {"colIndex": 3, "colType": "Numeric", "colName": "NR/M2"}, {"colIndex": 4, "colType": "Numeric", "colName": "NR/M3"}, {"colIndex": 5, "colType": "Numeric", "colName": "NR/M4"}, {"colIndex": 6, "colType": "Numeric", "colName": "NR/M5"}, {"colIndex": 7, "colType": "Numeric", "colName": "NR ART/M6"}, {"colIndex": 8, "colType": "Numeric", "colName": "NR ART/M1"}, {"colIndex": 9, "colType": "Numeric", "colName": "NR ART/M2"}, {"colIndex": 10, "colType": "Numeric", "colName": "NR ART/M3"}, {"colIndex": 11, "colType": "Numeric", "colName": "NR ART/MX"}]; // First filtering objects which will form the headers var rowHeaders = metadata.filter(function(obj) { return obj.colType == "String"; }); var colHeaders = metadata.filter(function(obj) { return obj.colType == "Numeric"; }); // Now we need the grouping on colName with value before slash. // These will form the group header. Count will determine the colspan. var colHeadersMain = {}; metadata.forEach(function(obj) { if (obj.colType == "String") { return } // Only for Numeric colType // Check if the key has been stored in the colHeadersMain if (obj.colName.split('/')[0] in colHeadersMain) { // If yes, then increment the value of the key for object colHeadersMain colHeadersMain[obj.colName.split('/')[0]]++; } else { // If not, reset the value colHeadersMain[obj.colName.split('/')[0]] = 1; } }); // Variables to hold jQuery elements var $table = $("<table>"), $thead = $("<thead>"), $row1 = $("<tr>"), $row2 = $("<tr>"); // Iterate row headers and form the first row // Hard-coding the rowspan. // ToDo: Maintain count, similar to column headers. rowHeaders.forEach(function(obj, idx) { var $th = $("<th rowspan='2'>"); $th.text(obj.colName); $row1.append($th); }); // Iterate col grouping headers and continue the row // colpsan is the group count that we created earlier for (var key in colHeadersMain) { var $th = $("<th colspan='" + colHeadersMain[key] + "'>"); $th.text(key); $row1.append($th); } // Add the first header row to thead $thead.append($row1); // Iterate next line of col headers colHeaders.forEach(function(obj, idx) { var $th = $("<th>"); $th.text(obj.colName.split('/')[1]); $row2.append($th); }); // Add to the thead $thead.append($row2); // Add to the table $table.append($thead); // Add to the page / element $("#wrap").append($table); // Done.
table, td, th { border: 1px solid gray; border-collapse: collapse; } th, td { padding: 4px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="wrap"></div>
As you did not tag jQuery in your post, here's a plain-vanilla JavaScript solution (although you did use a $
in the code of your post, which could indicate jQuery). 由于您没有在帖子中标记jQuery,因此这是一个普通的JavaScript解决方案(尽管您确实在帖子代码中使用了
$
,这可能表示jQuery)。
The code below, when applied to the metadata
will parse it into a format that's a little more conducive to what you want to do: 下面的代码应用于
metadata
会将其解析为一种更有利于您要做的事情的格式:
var columns = [];
metadata.forEach(function(column, index, array) { // parse into a more friendly format for making columns
var col = {}, // will be the column
parts = column.colName.split('/'), // you're splitting on the column name in your post
match = null, // for lookup, leaving null for falsy test later
i = 0; // iterator / index
col.name = parts[0]; // store the name
col.type = column.colType; // and type
col.index = column.colIndex; // and index, if you want to use it later
col.subColumns = []; // make an empty array for any subcolumns that may exist so we can concat later
if (parts.length > 1) {
col.subColumns.push({ // subcolumn, push it into the array
"name": parts[1],
"index": col.index
});
}
for (i = 0; i < columns.length; i += 1) {
if (columns[i].name === col.name) { // [parent] column already exists
match = i; // store the index
break; // exit the loop
}
}
if (match) { // index found
columns[i].subColumns = columns[i].subColumns.concat(col.subColumns); // concat the subcolumns
} else {
columns.push(col); // did not exist, add it to the array
}
});
Once that's been done, loop through the columns
variable twice to make your two rows (assumes variables for thead
, tr
, and th
elements). 完成此操作后,循环遍历
columns
变量两次以创建两行(假定thead
, tr
和th
元素的变量)。
columns.forEach(function(column, index, array) { // loop through once to make "parent" headers
th = document.createElement('th'); // create th element
th.colSpan = column.subColumns.length; // set a colSpan as necessary
if (!column.subColumns.length) { // if there are no subcolumns, make the header span two rows
th.rowSpan = 2;
}
th.innerText = column.name; // set the header text
tr.appendChild(th); // add to row
});
columns.forEach(function(column, index, array) { // loop through a second time to get the child headers
column.subColumns.forEach(function(subColumn, index, array) { // loop through the child headers
th = document.createElement('th'); // create th
th.innerText = subColumn.name; // set the header text
tr.appendChild(th); // add to row
});
});
Here is is in action: 这是实际的:
var metadata = [{ "colIndex": 0, "colType": "String", "colName": "PM" }, { "colIndex": 1, "colType": "String", "colName": "PROD" }, { "colIndex": 2, "colType": "Numeric", "colName": "NR/M1" }, { "colIndex": 3, "colType": "Numeric", "colName": "NR/M2" }, { "colIndex": 4, "colType": "Numeric", "colName": "NR/M3" }, { "colIndex": 5, "colType": "Numeric", "colName": "NR/M4" }, { "colIndex": 6, "colType": "Numeric", "colName": "NR/M5" }, { "colIndex": 7, "colType": "Numeric", "colName": "NR ART/M6" }, { "colIndex": 8, "colType": "Numeric", "colName": "NR ART/M1" }, { "colIndex": 9, "colType": "Numeric", "colName": "NR ART/M2" }, { "colIndex": 10, "colType": "Numeric", "colName": "NR ART/M3" }, { "colIndex": 11, "colType": "Numeric", "colName": "NR ART/MX" }], columns = [], thead = document.getElementById('dynamic'), // cache this DOM lookup tr = document.createElement('tr'), th; // placeholder for th elements that will be created metadata.forEach(function(column, index, array) { // parse into a more friendly format for making columns var col = {}, // will be the column parts = column.colName.split('/'), // you're splitting on the column name in your post match = null, // for lookup, leaving null for falsy test later i = 0; // iterator / index col.name = parts[0]; // store the name col.type = column.colType; // and type col.index = column.colIndex; // and index, if you want to use it later col.subColumns = []; // make an empty array for any subcolumns that may exist so we can concat later if (parts.length > 1) { col.subColumns.push({ // subcolumn, push it into the array "name": parts[1], "index": col.index }); } for (i = 0; i < columns.length; i += 1) { if (columns[i].name === col.name) { // [parent] column already exists match = i; // store the index break; // exit the loop } } if (match) { // index found columns[i].subColumns = columns[i].subColumns.concat(col.subColumns); // concat the subcolumns } else { columns.push(col); // did not exist, add it to the array } }); columns.forEach(function(column, index, array) { // loop through once to make "parent" headers th = document.createElement('th'); // create th element th.colSpan = column.subColumns.length; // set a colSpan as necessary if (!column.subColumns.length) { // if there are no subcolumns, make the header span two rows th.rowSpan = 2; } th.innerText = column.name; // set the header text tr.appendChild(th); // add to row }); thead.appendChild(tr); // add row to thead tr = document.createElement('tr'); // reset row columns.forEach(function(column, index, array) { // loop through a second time to get the child headers column.subColumns.forEach(function(subColumn, index, array) { // loop through the child headers th = document.createElement('th'); // create th th.innerText = subColumn.name; // set the header text tr.appendChild(th); // add to row }); }); thead.appendChild(tr); // add row to thead
th {border: 1px solid black;}
<table> <thead id="dynamic"></thead> </table>
jQuery, if you're using it, can make this syntax a little more "sugary" (mostly in making the rows and header cells, see below), but the principle will be the same. jQuery,如果您正在使用它,可以使此语法更加“有用”(主要是在制作行和标题单元格,请参见下文),但是原理是相同的。
columns.forEach(function(column, index, array) { // loop through once to make "parent" headers
th.clone().attr({
"colSpan": column.subColumns.length,
"rowSpan": column.subColumns.length === 0 ? 2 : 1
}).text(column.name).appendTo(tr);
});
tr.appendTo(thead);
tr = $('<tr />');
columns.forEach(function(column, index, array) { // loop through a second time to get the child headers
column.subColumns.forEach(function(subColumn, index, array) { // loop through the child headers
th.clone().text(subColumn.name).appendTo(tr);
});
});
tr.appendTo(thead);
After some hours i find an answer to my problem. 几个小时后,我找到了解决我问题的答案。 In this first part i create the tr and th (th non Unique)
在第一部分中,我创建了tr和th(第一个非唯一的)
var a = [], l = 0;
for (var i = 0; i < metadata.length; i++) {
var d = {
"colName": metadata[i].colName.split("/"),
"colType": metadata[i].colType
};
a.push(d);
if (metadata[i].colType == "Numeric") {
trl = metadata[i].colName.split("/").length;
}
}
for (var l = 0; l < trl; l++) {
var tr = $("<tr/>").appendTo("thead");
}
for (var j = 0; j < a.length; j++) {
if (a[j].colType == "String") {
$("<th/>").addClass("string").attr("rowspan", l).html(a[j].colName).appendTo("thead tr:nth(0)");
} else {
for (var k = 0; k < a[j].colName.length; k++) {
$("<th/>").addClass("numeric").html(a[j].colName[k]).appendTo("thead tr:nth(" + k + ")");
}
}
}
This part is adapted from here . 这部分从这里改编。 Now i clean up the table thead living just unique th.
现在,我收拾桌子thead居住唯一。
$('table tr').each(function () {
var tr = this;
var counter = 0;
var strLookupText = '';
$('th.numeric', tr).each(function (index, value) {
var td = $(this);
if ((td.text() == strLookupText) || (td.text() == "")) {
counter++;
td.prev().attr('colspan', '' + parseInt(counter + 1, 10) + '').css({
textAlign: 'center'
});
td.remove();
} else {
counter = 0;
}
strLookupText = td.text();
});
});
The code it's a litle messy, but it's late. 代码有点混乱,但是已经晚了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.