Warning: validateDOMNesting(...): <table> cannot appear as a child of <tr> - reactjs

I'm trying to get this kind of work with reactjs. But it returns error <table> cannot appear as a child of <tr>
Here is my RoomRow.js
import React from 'react'
import {Link} from 'react-router-dom'
import { formatAssetName, dailyBookings, bookingArray } from '../helpers/rooms'
// Accept the 24 hour dayHours array as the day's booking data for a room
const rowMapper = (dayHours, props) => {
let tableRow = []
// Loop through each hour from 8AM to 9PM (starting at 8AM = 0)
for (var i = 0; i < 13; i++) {
// Extract the corresponding data from the 24 hour array
let bookingData = dayHours[i + 8]
// If the data for that hour is a number (not a booking object), there is no booking
// Add a <td> element that indicates the time slot is available
if (typeof bookingData == 'number') {
tableRow.push(<td className="table__cell--available" key={bookingData}>
<Link to="/createbooking" onClick={() => {
props.onSetRoom(props.room._id)
}} className="table__link--available">
</Link>
</td>)
// If the data is an array, there are two booking objects
} else if (Array.isArray(bookingData)){
// Determine which of the two bookings comes first and second
let firstBookingData = bookingData[0].firstHalfHour ?
bookingData[0] : bookingData[1]
let secondBookingData = bookingData[0].secondHalfHour ?
bookingData[0] : bookingData[1]
tableRow.push(
<table className="table--booking--split" key={bookingData}>
<tbody>
<tr>
<td className={`table__cell`}>
<span
onClick={() => props.onShowBooking(firstBookingData)}
className={`table__cell--booked table__cell--${firstBookingData.businessUnit // Class name will show the business unit that made the booking, and whether the <td> element should be fully shaded, or half shaded (indicating a half-hour booking)
.replace(/ /g, '-')
.toLowerCase()}
`}
>
</span>
</td>
<td className={`table__cell`}>
<span
onClick={() => props.onShowBooking(secondBookingData)}
className={`table__cell--booked table__cell--${secondBookingData.businessUnit // Class name will show the business unit that made the booking, and whether the <td> element should be fully shaded, or half shaded (indicating a half-hour booking)
.replace(/ /g, '-')
.toLowerCase()}
`}
>
</span>
</td>
</tr>
</tbody>
</table>
)
// If there is a booking object, add a <td> element with custom class name to enable stlying
} else {
tableRow.push(
<td className={`table__cell`}>
<span
onClick={() => props.onShowBooking(bookingData)}
className={`table__cell--booked table__cell--${bookingData.businessUnit // Class name will show the business unit that made the booking, and whether the <td> element should be fully shaded, or half shaded (indicating a half-hour booking)
.replace(/ /g, '-')
.toLowerCase()}
${bookingData.firstHalfHour ? 'table__cell--first-half-hour' : ''}
${
bookingData.secondHalfHour ? 'table__cell--second-half-hour' : ''
}`}
>
</span>
</td>
)
}
}
return tableRow
}
const RoomRow = props => (
<tr className="table__row">
<th scope="row" className="table__cell--align-left">
<Link to="/createbooking" onClick={() => props.onSetRoom(props.room._id)} className="table__link">{props.room.name}</Link>
<ul >
{Object.keys(props.room.assets).map(
asset =>
props.room.assets[asset] && (
<li key={asset} onClick={props.onShowBooking} className="table__data--asset">{formatAssetName(asset)}</li>
)
)}
</ul>
</th>
{rowMapper(
bookingArray(dailyBookings(props.date, props.bookings)),
props
)}
</tr>
)
export default RoomRow
This is my RoomsList.js
import React from 'react'
import RoomRow from './RoomRow'
import { roomSorter } from '../helpers/sorter'
const RoomsList = props => (
<table className="table">
<tbody>
<tr className="table__row table__row--header">
<th scope="colgroup" colSpan="15" className="table__cell--header table__cell--level table__cell--align-left">
Level Eight
</th>
</tr>
<tr className="table__row table__row--subheader">
<th scope="col" className="table__cell--header table__cell--align-left">
Room
</th>
<th scope="col" className="table__cell--header">
8am
</th>
<th scope="col" className="table__cell--header">
9am
</th>
<th scope="col" className="table__cell--header">
10am
</th>
<th scope="col" className="table__cell--header">
11am
</th>
<th scope="col" className="table__cell--header">
12pm
</th>
<th scope="col" className="table__cell--header">
1pm
</th>
<th scope="col" className="table__cell--header">
2pm
</th>
<th scope="col" className="table__cell--header">
3pm
</th>
<th scope="col" className="table__cell--header">
4pm
</th>
<th scope="col" className="table__cell--header">
5pm
</th>
<th scope="col" className="table__cell--header">
6pm
</th>
<th scope="col" className="table__cell--header">
7pm
</th>
<th scope="col" className="table__cell--header">
8pm
</th>
</tr>
</tbody>
<tbody className="table__body">
{props.rooms &&
roomSorter(props.rooms, '8').map((room, i) => (
<RoomRow key={i}
key={room._id}
room={room}
bookings={room.bookings}
date={props.date === null ? new Date() : props.date}
onShowBooking={props.onShowBooking}
onSetRoom={props.onSetRoom}
/>
))}
</tbody>
<tbody>
<tr className="table__row table__row--header">
<th scope="colgroup" colSpan="15" className="table__cell--header table__cell--level table__cell--align-left">
Level Thirteen
</th>
</tr>
<tr className="table__row table__row--subheader">
<th scope="col" className="table__cell--header table__cell--width table__cell--align-left">
Room
</th>
<th scope="col" className="table__cell--header">
8am
</th>
<th scope="col" className="table__cell--header">
9am
</th>
<th scope="col" className="table__cell--header">
10am
</th>
<th scope="col" className="table__cell--header">
11am
</th>
<th scope="col" className="table__cell--header">
12pm
</th>
<th scope="col" className="table__cell--header">
1pm
</th>
<th scope="col" className="table__cell--header">
2pm
</th>
<th scope="col" className="table__cell--header">
3pm
</th>
<th scope="col" className="table__cell--header">
4pm
</th>
<th scope="col" className="table__cell--header">
5pm
</th>
<th scope="col" className="table__cell--header">
6pm
</th>
<th scope="col" className="table__cell--header">
7pm
</th>
<th scope="col" className="table__cell--header">
8pm
</th>
</tr>
</tbody>
<tbody className="table__body">
{props.rooms &&
roomSorter(props.rooms, '13').map((room, i) => (
<RoomRow key={i}
key={room._id}
room={room}
bookings={room.bookings}
date={props.date === null ? new Date() : props.date}
onShowBooking={props.onShowBooking}
onSetRoom={props.onSetRoom}
/>
))
}
</tbody>
</table>
)
export default RoomsList
The error is
index.js:2177 Warning: validateDOMNesting(...): <table> cannot appear as a child of <tr>.
in table (at RoomRow.js:36)
in tr (at RoomRow.js:90)
in RoomRow (at RoomsList.js:61)
in tbody (at RoomsList.js:58)
in table (at RoomsList.js:6)
How can I fix this error?

The error is explicite. You cannot nest tables. However you can simulate it using colspan and rowspan.
Example:
<table border="1" cellpadding="5">
<tr>
<td rowspan="2">table cell</td>
<td>sub table cell</td>
<td>sub table cell</td>
</tr>
<tr>
<td>sub table cell</td>
<td>sub table cell</td>
</tr>
<tr>
<td>table</td>
<td colspan="2">table cell</td>
</tr>
<tr></tr>
</table>

Natively in react there is not but you may want to look into this https://www.npmjs.com/package/react-nested-table or https://react-table.js.org/#/story/readme

Related

ReactJS: Number in row table

here I want to generate a number in the table. but I'm stuck here, how do I create a number table in reactjs? Thanks.
expectation
but the result
My Code:
<table width="100%" cellpadding="0">
<thead>
<tr>
<th scope="col" class="p-3">No. </th>
<th scope="col" class="p-3">Kompetitor</th>
<th scope="col" class="">Jumlah Witel : 11</th>
</tr>
</thead>
<tbody>
{lists.length > 0 &&
lists.map((item, index) => (
<tr key={item.kompetitor}>
<td className="pl-3">
1.
</td>
<td width="20%" className="pl-6">
{item.kompetitor === "stroomnet"
? "Icon Net"
: item.kompetitor}
</td>
<td width="80%">
<ProgressBar
total={
lists.map((item) => Number(item.count))
// .reduce((prev, curr) => prev + curr, 0)
}
status={status}
count={Number(item.count) || 0}
percent={convertPercent(index)}
/>
</td>
</tr>
))}
</tbody>
</table>
Use the index passed on the map method to create the indexed table
Change this line
<td className="pl-3">
1.
</td>
To this
<td className="pl-3">
{index+1}.
</td>

Generating a button for each row in ReactJs

I am trying to generate a delete button for the Action column in each row that is being generated in following table using react. How can I achieve that?
<Table>
<thead>
<tr>
<th>
Id
</th>
<th>
Description
</th>
<th>
Protocol
</th>
<th>
Last Seen
</th>
<th>
Action
</th>
</tr>
</thead>
<tbody>
{table.map((item) => (
<tr key={item.id}>
{Object.values(item).map((val) => (
<td>{val}</td>
))}
</tr>
))}
</tbody>
</Table>
here is the sample code
import React from "react";
const data = [1, 2, 3];
function Login() {
const deleteData = (dataId) => {
console.log(dataId);
};
return (
<>
<table>
<thead>
<tr>
<th>Id</th>
<th>Description</th>
<th>Protocol</th>
<th>Last Seen</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{data.map((val) => (
<tr key={val}>
<td>{val}</td>
<td>{"Desc"}</td>
<td>{"Prot"}</td>
<td>{"Las"}</td>
<td>
{" "}
<button onClick={() => deleteData(val)}>{"delete"}</button>
</td>
</tr>
))}
</tbody>
</table>
</>
);
}
export default Login;

Get Total of NgFor item Angular

I have an leave array with leave counts of different leave types, I have to return the total of every leave types
array = {
"Jan 2021": [
{
"WFH": 17.5
},
{
"CL": 3.5
}
],
"Feb 2021": [
{
"WFH": 19.5
},
{
"CL": 2.5
}
],
"Mar 2021": [
{
"WFH": 13
}
]
}
This is my html file:
<table class="table table-statitics2 table-bordered" aria-label="Leave">
<thead>
<tr>
<th scope="col"></th>
<th scope="col" class="casual">CL</th>
<th scope="col" class="earned">EL</th>
</tr>
</thead>
<tbody *ngIf="leaves">
<tr *ngFor="let item of leaves | keyvalue : keepOriginalOrder">
<td class="date">{{item.key}}</td>
<td>{{getMonthyItem(item.value, "CL")}}</td>
<td>{{getMonthyItem(item.value, "EL")}}</td>
</tr>
</tbody>
<tfoot>
<tr>
<th colspan="2" class="text-center text-danger" scope="row">Total</th>
<th scope="row">Total of CL</th>
<th scope="row">Total of EL</th>
</tr>
</tfoot>
</table>
this is my function to return Leave Count
getMonthyItem(items, object)
{
let result = '';
items.forEach(element => {
if(Object.keys(element) == object)
{
result = element[object];
}
});
return result;
}
How can I return total of every leave types on footer section of table, also is there any simple way to return leave counts directly on html page without the function, that have used.
Expected result is,
CL
WFH
Jan 2021
3.5
17.5
Feb 2021
2.5
19.5
Mar 2021
1
13
Total
7
50
Thanks............................................................................................................................................................................................
<table class="table table-statitics2 table-bordered" aria-label="Leave">
<thead>
<tr>
<th scope="col"></th>
<th scope="col" class="casual">CL</th>
<th scope="col" class="earned">EL</th>
</tr>
</thead>
<tbody *ngIf="leaves">
<tr *ngFor="let item of leaves | keyvalue : keepOriginalOrder">
<td class="date">{{item.key}}</td>
<td>{{getMonthyItem(item.value, "CL")}}</td>
<td>{{getMonthyItem(item.value, "EL")}}</td>
</tr>
</tbody>
<tfoot>
<tr>
<th colspan="2" class="text-center text-danger" scope="row">Total</th>
<th scope="row">Total of CL</th>
<th scope="row">Total of EL</th>
</tr>
<tr>
<td>total('CL')</td>
<td>total('EL')</td>
</tr>
</tfoot>
</table>
and then in your .ts function define a new function. As I see you already keep as field the leaves which contains all the information. So it would be
public total (type: string): number {
let sum = 0;
Object.keys(this.leaves).forEach(key => {
this.leaves[key].forEach(element => {
sum = sum + (element[type] ? element[type] : 0);
});
});
return sum;
}
The way I would go about it is to calculate the total in a function and add an extra row manually with the data in:
HTML:
<table class="table table-statitics2 table-bordered" aria-label="Leave">
<thead>
<tr>
<th scope="col"></th>
<th scope="col" class="casual">CL</th>
<th scope="col" class="earned">EL</th>
</tr>
</thead>
<tbody *ngIf="leaves">
<tr *ngFor="let item of leaves | keyvalue : keepOriginalOrder">
<td class="date">{{item.key}}</td>
<td>{{getMonthyItem(item.value, "CL")}}</td>
<td>{{getMonthyItem(item.value, "EL")}}</td>
</tr>
<tr>
<td class="date">Total</td>
<td>{{total(leaves, "CL")}}</td>
<td>{{total(leaves, "WFH")}}</td>
</tr>
</tbody>
<tfoot>
<tr>
<th colspan="2" class="text-center text-danger" scope="row">Total</th>
<th scope="row">Total of CL</th>
<th scope="row">Total of EL</th>
</tr>
</tfoot>
</table>
Function:
total(items, object)
{
let result = 0;
items.forEach(x => {
if(Object.keys(x) == object)
{
result = result + x[object];
}
});
return result;
}

Is it possible to add each value of ngFor as one value?

There are some values returned by ngFor in Total Column. Now I wanted to add those value to get a one grandTotal. I didn't get the idea. Anyone can help me??
In below second table:
I want {{sales.Total}} values to be added and return grand total.
/*****First Table*****/
<table class="table">
<thead>
<tr>
<th scope="col">S.N</th>
<th scope="col">Items</th>
<th scope="col">Quantity</th>
<th scope="col">Rate</th>
<th scope="col">Total</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let sales of salesTransaction, let i = index">
<th>{{i+1}}</th>
<!-- <td mat-cell *matCellDef="let salesTransaction">{{salesTransaction.ProductName}}</td> -->
<td>{{sales.ProductName}}</td>
<td>{{sales.Quantity}}</td>
<td>{{sales.Rate}}</td>
<td>{{sales.Total}}</td>
</tr>
</tbody>
</table>
/*****Second Table*****/
<table class="right-table">
<tbody>
<tr>
<th>Sub-Total</th>
<td *ngFor="let sales of salesTransaction">{{sales.Total}}</td>
</tr>
<hr class="divider">
<tr>
<th>Tax</th>
<td>Happy</td>
</tr>
<hr class="divider">
<tr>
<th>Grand Total</th>
<td>0000</td>
</tr>
</tbody>
</table>
You need to create a method that returns grand total
getGrandTotal(): number {
return this.salesTransaction.reduce((acc, val) => acc += val.Total, 0);
}
<tr>
<th>Grand Total</th>
<td>{{getGrandTotal()}}</td>
</tr>
<table class="right-table">
<tbody>
<tr>
<th>Sub-Total</th>
<td *ngFor="let sales of salesTransaction">{{sales.Total}}</td>
</tr>
<hr class="divider">
<tr>
<th>Tax</th>
<td>Happy</td>
</tr>
<hr class="divider">
<tr>
<th>Grand Total</th>
<td>{{salesTransaction.reduce((total, value) => total += value.Total, 0)}}</td>
</tr>
</tbody>
</table>

Export only filtered data into csv in angular smart table

We have implemented a report table using angular smart table.When user applied search criteria using st-search , we need to export all items into csv.We have used ng-csv directive for exporting. When use st-table array collection, the only first page data is getting.That mean total 7 records after filtering and first page showing 5 items, only this data(5 items) is exported.How can export all filtered data?
<table class="table table-striped" st-table="displayed">
<thead>
<tr>
<th st-sort="firstName">first name</th>
<th st-sort="lastName">last name</th>
<th st-sort="birthDate">birth date</th>
<th st-sort="balance">balance</th>
<th >email</th>
</tr>
<tr>
<th>
<input st-search="firstName" placeholder="search for firstname" class="input-sm form-control" type="search"/>
</th>
<th colspan="4">
<input st-search placeholder="global search" class="input-sm form-control" type="search"/>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in displayed">
<td>{{row.firstName | uppercase}}</td>
<td>{{row.lastName}}</td>
<td>{{row.birthDate | date}}</td>
<td>{{row.balance | currency}}</td>
<td><a ng-href="mailto:{{row.email}}">email</a></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5" class="text-center">
<div st-pagination="" st-items-by-page="5" st-displayed-pages="10"></div>
</td>
</tr>
</tfoot>
You can have access to the filtered collection through the table controller api. So you just need to create a directive which requires the stTable controller:
.directive('stExport',function(){
return {
require:'^stTable',
link:function(scope, element, attr,ctrl){
element.bind('click',function(){
alert(ctrl.getFilteredCollection().length);
})
};
}
have a look at that running example

Resources