How to create table with multiline cells in React-bootstrap? - javascript

I want to create table where some cells contain several lines.
It's work if I do it:
<Table bordered>
<thead>
<tr>
<th>Date</th>
<th>Analysed ID</th>
<th>Analysed Name</th>
<th>Solve To change</th>
</tr>
</thead>
<tbody>
<tr>
<td rowSpan="3">Date</td>
</tr>
<tr>
<td>ID</td>
<td>Name</td>
<td>Decision</td>
</tr>
<tr>
<td>ID</td>
<td>Name</td>
<td>Decision</td>
</tr>
</tbody>
</Table>
I got it:
Table with multiline cell
And now I want to add my 3 "TR" tags in one component, because after I want use for-cycle to create many such components. But components must return content in one closed tag. I tried to contain my 3 "tr" in one parent "tr", but I got error. What can I do here?

It is not possible to create a React Component that returns three elements without wrapping them in another element, such as a div. Otherwise, you'll get the following error:
A valid ReactComponent must be returned. You may have returned undefined, an array or some other invalid object.
Your case here is a bit special, because you cannot have div's as the immediate child of table or tbody, so that's a problem...
What you can do however, is to create a class function that returns an array. Like this:
class MyApp extends React.Component {
getTr = () => {
return [
<tr key={0}>
<td rowSpan="3">Date</td>
</tr>,
<tr key={1}>
<td>ID</td>
<td>Name</td>
<td>Decision</td>
</tr>,
<tr key={2}>
<td>ID</td>
<td>Name</td>
<td>Decision</td>
</tr>
];
}
render() {
return (
<table className="table">
<thead>
<tr>
<th>Date</th>
<th>Analysed ID</th>
<th>Analysed Name</th>
<th>Solve To change</th>
</tr>
</thead>
<tbody>
{this.getTr()}
{this.getTr()}
{this.getTr()}
</tbody>
</table>
);
}
}
ReactDOM.render(<MyApp />, document.getElementById("app"));
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

You need to include tr tags in one div tag.
The right way to rowSpan is this:
var MyRow = React.createClass({
render: function () {
return (
<div>
<tr>
<td rowSpan="2">{this.props.item.date}</td>
<td>{this.props.item.data[0].id}</td>
<td>{this.props.item.data[0].name}</td>
<td>{this.props.item.data[0].solve}</td>
</tr>
<tr>
<td>{this.props.item.data[1].id}</td>
<td>{this.props.item.data[1].name}</td>
<td>{this.props.item.data[1].solve}</td>
</tr>
</div>
);
}
});
This is my working example: http://jsfiddle.net/andrea689/e33pd14L/

Related

Webcomponents based on <table>. Slot out of flow

I'm try create data-grid with "web component" based on TABLE. I'm use slot in TBODY to append new items. But TR rows rendered out of TBODY. I don't understand this behavior.
shadowDom disallow use TABLE and TR elements, possibly the reason is this, but using HTMLElement.appendChild() also doesn't work
<html>
<head>
<script type="module">
class DataGrid extends HTMLElement {
TEMPLATE_ID = '#data-grid';
constructor() {
super();
this._records = [];
}
connectedCallback() {
let shadow = this.attachShadow({mode: 'open'});
this._render(shadow);
}
_render(shadow){
let tmpl = document.querySelector(this.TEMPLATE_ID);
shadow.appendChild(tmpl.content.cloneNode(true));
//this.appendChild(tmpl.content.cloneNode(true)); //
}
}
customElements.define('data-grid', DataGrid);
</script>
</head>
<body>
<template id="data-grid">
<table border="1">
<thead>
<tr>
<th>id</th>
<th>time</th>
<th>voltage</th>
<tr>
</thead>
<tbody>
<slot></slot>
<tbody>
</table>
</template>
<data-grid>
<!-- need replaced to component
<grid-row time="" voltage="">
-->
<tr>
<td>1</td>
<td>123123123120</td>
<td>12.0</td>
</tr>
<tr>
<td>2</td>
<td>123123133324</td>
<td>12.1</td>
</tr>
<tr>
<td>1</td>
<td>123123122330</td>
<td>12.2</td>
</tr>
</data-grid>
</body>
From the <TR> documentation on MDN:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/tr
Permitted parents
<table> (only if the table has no child <tbody> element, and even
then only after any <caption>, <colgroup>, and <thead>
elements); otherwise, the parent must be <thead>, <tbody> or
<tfoot>
So
<data-grid>
<tr>
is not valid HTML
move (invalid) lightDOM to a <table> inside <data-grid> shadowDOM
note: attachShadow() both sets and returns this.shadowRoot for free
No need to create your own shadow variable.
psuedo code:
const table = this.shadowRoot.querySelector("TABLE");
this.querySelectorAll("TR").forEach(table.appendChild);

Programmatically create HTML table from D3 nested JSON object

I'm trying to make tables for a dashboard using React/D3. One of them is similar to this HTML hard-coded table which I'm trying to make:
table, td{
border: 1px solid black;
}
<table>
<thead>
<td>Location</td>
<td>State</td>
<td># Jobs</td>
</thead>
<tbody>
<tr>
<td rowspan="2">Cell 1 spanning if we have multiple values for this key</td>
<td>SUCCESSFUL</td>
<td>75</td>
</tr>
<tr>
<td>FAILED</td>
<td>22</td>
</tr>
</tbody>
</table>
<br />
Data
The data is retrieved from a SQL-Server database through node-mssql and express and then stored in react state, I pull 7 days worth of data and filter this down to 1 day per component in my react app as i need it.
It returns as normal and has NO nesting in it e.g.
{
"location": "Ireland",
"state": "Finished",
"finish_time": "2018-10-18T12:00:00",
"seconds_passed": 30
}
D3
With D3 I aggregated this data so that, it would be aggregated by location, then by state and then a count of the rows in that aggregation. I achieved this with nest and rollup:
dailyJobStatusCounts = () => {
return (
nest()
.key( row => row.location)
.key( row => row.state)
.rollup(function(values) { return values.length; })
.entries(this._filterTwentyFourHours())
);
}
This returns an object that looks like this:
[{"key":"Ireland","values":[{"key":"SUCCEEDED","value":14},{"key":"FAILED","value":7}]}]
Rendering to HTML in React
My issue occurs around my lack of understanding of how to render this nested JSON object as a HTML table. When attempting to render, I have tried two variations:
React
<table>
<thead>
<tr>
<th>Location</th>
<th>State</th>
<th># Jobs</th>
</tr>
</thead>
<tbody>
{data.map(row => {
return <tr>
<td>{row.key}</td>
{ row.values.map( v => {
return <React.Fragment>
<td>{v.key}</td>
<td>{v.value}</td>
</React.Fragment>
})}
</tr>
})}
</tbody>
</table>
Which renders the table like this:
HTML Output
table, td {
border: 1px solid black;
}
<table>
<thead>
<tr>
<th>Location</th>
<th>State</th>
<th>Jobs</th>
</tr>
</thead>
<tbody>
<tr>
<td>ie11</td>
<td>SUCCEEDED</td>
<td>14</td>
<td>FAILED</td>
<td>7</td>
</tr>
</tbody>
</table>
Or the other variation:
React
<table>
<thead>
<tr>
<th>Location</th>
<th>State</th>
<th># Jobs</th>
</tr>
</thead>
<tbody>
{data.map(row => {
return <tr>
<td>{row.key}</td>
{ row.values.map( v => {
return <tr>
<td>{v.key}</td>
<td>{v.value}</td>
</tr>
})}
</tr>
})}
</tbody>
</table>
HTML Output
table, td {
border: 1px solid black;
}
<table>
<thead>
<tr>
<th>Location</th>
<th>State</th>
<th># Jobs</th>
</tr>
</thead>
<tbody>
<tr>
<td>ie11</td>
<tr>
<td>SUCCEEDED</td>
<td>13</td>
</tr>
<tr>
<td>FAILED</td>
<td>7</td>
</tr>
</tr>
</tbody>
</table>
I see that some of the HTML being output for table is not valid as I have nested values, however I am struggling to get my head around how I can map this JSON object to display the HTML table with the rowspan mentioned at the beginning of this question. Thanks in advance for any answers.
Looked at a somewhat similar SO question which is close, but I'm not sure it answers my use-case here

How to make footable work in a table that's being populated with JS from JSON?

I have something like this:
<table id="thatTable" class="table toggle-circle">
<thead>
<tr>
<th>ID</th>
<th>FieldA</th>
<th data-hide="all">FieldB</th>
<th data-hide="all">FieldC</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="4">
<div class="text-right">
<ul class="pagination"></ul>
</div>
</td>
</tr>
</tfoot>
</table>
Then a JS like this:
var fillThatTable = function (list) {
$.each(list, function (index, item) {
$('#thatTable tbody').append($('<tr>')
.append($('<td>').text(item.ID))
.append($('<td>').text(item.FieldA))
.append($('<td>').text(item.FieldB))
.append($('<td>').text(item.FieldC))
)
);
});
};
Everything works fine, the table gets the data and shows it all. Problem comes when I want to set footable() to that table, like so:
$(document).ready(function () {
fillThatTable();
$('#thatTable').footable();
});
And instead of getting something beautiful, I just receive an average filtered table, almost like I didn't put that $('#thatTable').footable(). I checked the JS are imported, they are. Is it maybe because the table doesn't have anything in the tbody? What am I missing?
Dream:
Reality:
I've updated PM's fiddle to make an easier use of FooTable: http://jsfiddle.net/0pb4x7h6/1
If your html changes to this:
<table id="thatTable" class="table toggle-circle">
<thead>
<tr>
<th data-name="ID">ID</th>
<th data-name="FieldA">FieldA</th>
<th data-name="FieldB" data-breakpoints="all">FieldB</th>
<th data-name="FieldC" data-breakpoints="all">FieldC</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="4">
<div class="text-right">
<ul class="pagination"></ul>
</div>
</td>
</tr>
</tfoot>
</table>
Then you can simplify your script to this:
$(document).ready(function () {
var list = [
{"ID":"1","FieldA":"A1","FieldB":"B1","FieldC":"C1"},
{"ID":"2","FieldA":"A2","FieldB":"B2","FieldC":"C2"},
{"ID":"3","FieldA":"A3","FieldB":"B3","FieldC":"C3"}
];
// No need for this
//fillThatTable();
$('#thatTable').footable({
rows: list
});
});

Creating a custom table row

I am trying to create a custom table row but having difficulty getting it to behave properly. I've tried the two below methods and they give bizarre results. I realize that this is very easy to to without custom elements but this is a small example of a much larger project. What can I change to achieve the desired result?
class customTableRow extends HTMLElement {
constructor(){
super();
var shadow = this.attachShadow({mode: 'open'});
this.tableRow = document.createElement('tr');
var td = document.createElement('td');
td.innerText = "RowTitle";
this.tableRow.appendChild(td);
var td2 = document.createElement('td');
td2.innerText = "RowContent";
td2.colSpan = 4;
this.tableRow.appendChild(td2);
shadow.appendChild(this.tableRow);
}
}
customElements.define('custom-tr', customTableRow);
//Attempt 2
var newTr = new customTableRow;
document.getElementById('table2Body').appendChild(newTr);
td {
border: 1px solid black;
}
<span>Attempt 1:</span>
<table>
<thead>
<tr>
<th>One</th>
<th>Two</th>
<th>Three</th>
<th>Four</th>
<th>Five</th>
</tr>
</thead>
<tbody>
<custom-tr />
</tbody>
</table>
<hr>
<span>Attempt 2:</span>
<table id="table2">
<thead>
<tr>
<th>One</th>
<th>Two</th>
<th>Three</th>
<th>Four</th>
<th>Five</th>
</tr>
</thead>
<tbody id="table2Body">
<!-- It should append here -->
</tbody>
</table>
<hr>
<span>This is how I want it to look:</span>
<table id="table2">
<thead>
<tr>
<th>One</th>
<th>Two</th>
<th>Three</th>
<th>Four</th>
<th>Five</th>
</tr>
</thead>
<tbody>
<tr>
<td>Row Title</td>
<td colspan="4">Row Content</td>
</tbody>
</table>
A <table> element and its subcomponents <tbody>, <tr> require a very specific syntax. For example, only <tr> elements are authorized as children of <tbody>.
Therefore you cannot define a element and insert it in <tbody> or <table>. If you do that it will be moved outside of the <table> at parsing. Hence the display of your first example (look the code in the Dev Tools).
Instead you should define a customized tag instead like in this answer to a similar question.
Or you should redefine a complete custom table structure with <custom-table>, <custom-tbody>... like in this other answer.
Also, you should use closing tag <custom-tr></custom-tr>, and insert your CSS rule in the Shadow DOM if you want it to by applied inside it.

jquery how to get the class of parent element using chlid id?

I'm trying to alert the table(parent) class on click using the child id <th id="first">.
alert($(this).parent('tr').attr('class')); using this i have got the class of the <tr>.
But i want to get the class of the table when i use alert($(this).parent('table').attr('class')); it showing alert says undefined can someone help me how can the parent class using the child id
<table class="table table-bordered">
<thead>
<tr class="sample">
<th id="first">Firstname</th>
<th id="last">Lastname</th>
<th id="user">Username</th>
</tr>
</thead>
<tbody>
<tr>
<td>arun </td>
<td>kumaresh</td>
<td>arun kumaresh</td>
</tr>
</tbody>
</table>
</div>
<script>
$(document).ready(function(){
$("#first").click(function(){
alert($(this).parent('tr').attr('class'));
});
});
</script>
Use .closest(TARGET_SELECTOR), For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
As .parent(SELECTOR), Get the parent of each element in the current set of matched elements, optionally filtered by a selector. (the parent() method traverses to the immediate parent)
$(document).ready(function() {
$("#first").click(function() {
alert($(this).closest('table').attr('class'));
});
$("#last").click(function() {
alert($(this).closest('thead').attr('class'));
});
$(".user").click(function() {
alert($(this).closest('table').attr('class'));
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<table class="table table-bordered">
<thead class='ANY_CLASS'>
<tr class="sample">
<th id="first">Firstname</th>
<th id="last">Lastname</th>
<th class="user">Username</th>
</tr>
</thead>
<tbody>
<tr>
<td>arun</td>
<td>kumaresh</td>
<td>arun kumaresh</td>
</tr>
</tbody>
</table>
simply use
alert($(this).closest('table').attr('class'));
refer closest here
https://api.jquery.com/closest/

Categories