Map through an array that creates a horizontal table - javascript

I am trying to map through an array and dynamically create a horizontal table, much like the image below here.
I am mapping through an array like so,
const glanceGames = this.state.gameData.map(game => {
return <GameTable
key={game.id}
home_team_name={game.home_name_abbrev}
away_team_name={game.away_name_abbrev}
home_score={game.linescore.r.home}
away_score={game.linescore.r.away}
status={game.status.status}
/>
})
and then using that data to populate the following component.
const GameTable = (props) => {
return (
<div>
<table>
<thead>
<tr>
<th>{props.status}</th>
</tr>
</thead>
<tbody>
<tr>
<td>{props.home_team_name}</td>
<td>{props.home_score}</td>
</tr>
<tr>
<td>{props.away_team_name}</td>
<td>{props.away_score}</td>
</tr>
</tbody>
</table>
</div>
)
}
However, the output is a vertical table rather than a horizontal one. I feel like this should be easy, yet I keep running into issues. Anu suggestions would be helpful! I am using React.

I don't think this is nothing to do with react, we can just do it with css:
...
render(){
<div style={{display: 'flex'}}>
{glanceGames}
</div>
}

Related

How do I dynamically generate table rows without jquery?

Currently, I have a table class as follows:
import React from "react";
import "./Table.css";
export default function Table({theadData, tbodyData}) {
return (
<>
<table>
<tr>
<th></th>
<th>2017</th>
</tr>
{Array.from(theadData).forEach(heading => {
<tr>
<td class="largeHeader" key={heading}>{heading}</td>
<td class="primaryCell">{tbodyData[heading].value}</td>
</tr>;
})}
</table>
</>
);
}
When I add console.log(heading) or console.log(tbodyData[heading].value) within the loop, I can see that they give the expected values. However, none of the rows are added on. Why is that and how can I solve this problem? (I'd prefer to avoid jquery and libraries of that nature if possible, but am open to ideas.)
There are several mistakes you made:
change forEach to map
replace {} with (), or add return before <tr>
put key on the root element which is <tr>
{Array.from(theadData).map(heading => (
<tr key={heading}>
<td className="largeHeader">{heading}</td>
<td className="primaryCell">{tbodyData[heading].value}</td>
</tr>
))}

Error when looping to an array in React JS

This is my code in "App.js" as the array I want to loop from, I wanted to loop from the array below and output the contents of it in the browser with a table.
This is my return
return (
<div className="container">
<h1> Expenses </h1>
<table className="table table-bordered">
<tr>
<th>Title</th>
<th>Amount</th>
<th>Date</th>
</tr>
{expenses.map((expense, index) => (
<tr data-index={index}>
<td>{expense.title}</td>
<td>{expense.amount}</td>
<td>{expense.date}</td>
</tr>
))}
</table>
</div>
);
This is the code from my component.
import './ExpenseItem.css';
function ExpenseItem(props) {
return (
<div className="expense-item" >
<div>{props.date.toISOString()}</div>
<div className="expense-item__description">
<h2>{props.title}</h2>
<div className="expense-item__price">{props.amount}</div>
</div>
</div>
)
}
export default ExpenseItem
This is the error that I am getting.
You need to convert dates to strings. In your code, you pass Date Objects to HTML. The data format should be String. You can see formatting options for dates on MDN.
<td>{expense.date.toString()}</td>
You're trying to output a Date object:
<td>{expense.date}</td>
Which, as the error states, is an object and not a simple value. So React has no way of knowing how to display it.
You can define the format and output that. For example:
<td>{expense.date.toLocaleDateString()}</td>
There are a variety of functions built-in to the Date object to format it, or you can combine multiple values from it into a custom format, or use a date formatting/parsing library, etc.
return (
<div className="container">
<h1> Expenses </h1>
<table className="table table-bordered">
<tr>
<th>Title</th>
<th>Amount</th>
<th>Date</th>
</tr>
{expenses.map((expense, index) => (
<tr data-index={index}>
<td>{expense.title}</td>
<td>{expense.amount}</td>
<td>{expense.date.toISOString()}</td>
</tr>
))}
</table>
</div>
);
Date object is not valid react child.
I think in App.js when you loop through the expenses array, you want to return the ExpenseItem component, passing it the current expense item as a prop, like this:
{expenses.map((expense, index) => (
<ExpenseItem item={expense} />
))}
And in ExpenseItem, since props is an object, you should change props.title to props.item.title etc.
Hope this helps!

Trying to get data of the row clicked of the table react js

I am new to react,and making app where I want to get data of the row being clicked on a table,I don't whether this approach is good or not need suggestions
So far i have used onClick listener but when I click on a table , it gives me [object,object] in console.log(contract),I have also tried to to use loop to view data in it but it gives me [object,object],here's my below code:
<table id="mytable" cellSpacing="0" width="100%">
<thead>
<tr>
<th>CarName</th>
<th>DriverName</th>
<th>Date</th>
<th>Pickup</th>
</tr>
</thead>
<tbody>
{
this.state.contracts.map((contract,index)=>{
return(
<tr key={index} data-item={contract} onClick={this.contractdetails}>
<td>{contract.car} </td>
<td>{contract.driver}</td>
<td>{contract.date}</td>
<td>{contract.pickup}</td>
</tr>
)})
}
</tbody>
</table>
onClickfunction
contractdetails=(e)=>{
const contract=e.currentTarget.getAttribute('data-item');
console.log(contract)
};
Use JSON.stringify while setting the data-item
<tr key={index} data-item={JSON.stringify(contract)} onClick={this.contractdetails}>
And use JSON.parse() while accessing it.
contractdetails=(e)=>{
const contract= JSON.parse(e.currentTarget.getAttribute('data-item'));
console.log(contract)
};
A better way is to just set index as data-index and you can access it from the state
this.state.contracts.map((contract,index)=>{
return(
<tr key={index} data-index={index} onClick={this.contractdetails}>
...
...
}
You can access it like below
contractdetails=(e)=>{
let index = +e.currentTarget.getAttribute('data-index')
console.log(this.state.contracts[index]);
};

Warning: validateDOMNesting(...): <div> cannot appear as a child of <tr> using React-bootstrap

I have this code. This and more is in the return statement of the render() method
<Table striped bordered condensed hover responsive>
<thead>
<tr>
<th style={{textAlign: 'center'}}>Imie Nazwisko/Nazwa firmy</th>
<th style={{textAlign: 'center'}}>ID</th>
<th style={{textAlign: 'center'}}>Raporty</th>
</tr>
</thead>
<tbody>
{
this.state.users && this.state.users.map((user, i) => (
<tr key={user.id}>
<td>
{user.userType === 'person' ? `${user.person.firstName} ${user.person.lastName}` : user.company.name}
</td>
<td>{user.id}</td>
<Table striped bordered hover responsive>
<tbody>
{
user.reports.map(report => (
<tr key={report.id}>
<td>{report.id}</td>
</tr>
))
}
</tbody>
</Table>
</tr>
))
}
</tbody>
</Table>
And this error code:
Warning: validateDOMNesting(...): <div> cannot appear as a child of <tr>.
in div (created by Table)
in Table (at ReportsComponent.js:59)
in tr (at ReportsComponent.js:54)
in tbody (at ReportsComponent.js:51)
in table (created by Table)
in div (created by Table)
in Table (at ReportsComponent.js:43)
in ReportsComponent (at NavigationComponent.js:67)
So the problem is I am not creating the div myself. I can see that Table is creating the div that's throwing the error.
I am using the Table component from react-bootstrap.
This code looks OK in the browser, and seems to work, but the error is just irritating. How can I solve it?
React Bootstrap generates a Table in form of div when adding the responsive property. To avoid this warning (note, not a blocking error) you could wrap the Table component in a td.
Or if you prefer you can write a wrapper around React Bootstrap's Table to make sure it gets surrounded by td if the responsive property is passed in.

React - table created incorrectly

I have a table in React where the user can add a variable number of rows.
<div>
<table class="table table-condensed table-bordered">
<tr>
<th>List Names</th>
<th>List Full Names</th>
<th>List Descriptions</th>
</tr>
{this.displayTableBody()}
</table>
<button style={{display:'inline-block'}} type="button"
className="btn btn-primary btn-small" onClick={this.addList}>
<span className="glyphicon glyphicon-plus"></span>
</button>
</div>
The rows are added by the displayTableBody method:
displayTableBody: function() {
var rows = Array.apply(null, Array(this.state.rowNr)).map(
function(e1, index) {
return <ListInput key={index} ref={index}/>
}
);
return(<div>{ rows }</div>);
}
One row is made of a ListInput component, which has the following render method:
render: function() {
return (
<tr>
<td>{this.displaySimpleInputField(
"List Name(<15 characters - A-Z, 0-9 and _ only)", this.setListName, "input")}</td>
<td>{this.displaySimpleInputField(
"List Full Name(<75 characters)", this.setListFullName, "input")}</td>
<td>{this.displaySimpleInputField(
"List Description(<225 characters)", this.setListDescription, "input")}</td>
</tr>
)
}
However, when I add a row, it is placed above the table header:
When working with tables, it is doubly important to write valid HTML, otherwise you get weird results like this. Specifically, the correct structure of a table is kinda like this:
<table>
<thead>
<tr><th></th></tr>
</thead>
<tbody>
<tr><td></td></tr>
</tbody>
</table>
Specifically, I'm pretty sure you can't place a div directly in table, like you do with your displayTableBody method. Try to rewrite your component to follow the HTML standard, I believe that's what causes your problem.
You are inserting div element directly inside a table, which is not correct html and it does break the layout, placing that element at the top of the table.
I would suggest restructuring your code as follows, and consider using times function from lodash:
displayTableBody: function() {
var rows = times(this.state.rowNr).map(
function(index) {
return <ListInput key={index} ref={index}/>
}
);
return(<tbody>{ rows }</tbody>);
}
And the table
<table class="table table-condensed table-bordered">
<thead>
<tr>
<th>List Names</th>
<th>List Full Names</th>
<th>List Descriptions</th>
</tr>
</thead>
{this.displayTableBody()}
</table>

Categories