How to restrict Table Header to display once in map function? - reactjs

I have a data store in state which needs to be displayed in a tabular format in UI using React. I am using a map function to display the data.
I am able to display the data but the header is being displayed after each row as they are iterated in a loop.
Please let me know how can i display the output in tabular format with header being displayed only once?
return method code in React:-
return (
<div>
<br />
<input
type="submit"
class="btn btn-info btn-sm"
value="Create Itinerary"
onClick={this.callItinAPI}
/>
<br />
<br />
{this.state.ItinData.map((item) => (
<div>
<table id="DisplayRequest">
<tr>
<th>TripName</th>
<th>Booking ID</th>
<th>Start Date</th>
<th>End Date</th>
</tr>
<tr>
<td>{item.Itinerary.TripName._text}</td>
<td>{item.Itinerary.Bookings.Booking.RecordLocator._text}</td>
<td>{item.Itinerary.StartDateLocal._text}</td>
<td>{item.Itinerary.EndDateLocal._text}</td>
</tr>
</table>
</div>
))}
</div>
);
Expected output:- Table header to displayed only once followed by all the data rows

You just need to extract the header from your loop :
<div>
{this.state.ItinData.length > 0 ? (
<table id={'DisplayRequest'}>
<tr>
<th>TripName</th>
<th>Booking ID</th>
<th>Start Date</th>
<th>End Date</th>
</tr>
{this.state.ItinData.map((item) => (
<tr>
<td>{item.Itinerary.TripName._text}</td>
<td>{item.Itinerary.Bookings.Booking.RecordLocator._text}</td>
<td>{item.Itinerary.StartDateLocal._text}</td>
<td>{item.Itinerary.EndDateLocal._text}</td>
</tr>
))}
</table>;
) : null}
</div>

return (
<div>
<br />
<input
type="submit"
class="btn btn-info btn-sm"
value="Create Itinerary"
onClick={this.callItinAPI}
/>
<br />
<br />
<div>
<table id="DisplayRequest">
<tr>
<th>TripName</th>
<th>Booking ID</th>
<th>Start Date</th>
<th>End Date</th>
</tr>
{this.state.ItinData.map((item) => (
<tr>
<td>{item.Itinerary.TripName._text}</td>
<td>{item.Itinerary.Bookings.Booking.RecordLocator._text}</td>
<td>{item.Itinerary.StartDateLocal._text}</td>
<td>{item.Itinerary.EndDateLocal._text}</td>
</tr>
))}
</table>
</div>
</div>
);
just move that td out side the loop

The issue with your code is, you have put the table header in the loop itself which is wrong. Try something like this:
{
( this.state.ItinData.length > 0 ) // conditional rendering if data exist
?
<table id={'DisplayRequest'}>
<tr>
<th>TripName</th>
<th>Booking ID</th>
<th>Start Date</th>
<th>End Date</th>
</tr>
// Use the map() function to iterate the array and display the table body here
{this.state.ItinData.map((item) => (
<tr>
<td>{item.Itinerary.TripName._text}</td>
<td>{item.Itinerary.Bookings.Booking.RecordLocator._text}</td>
<td>{item.Itinerary.StartDateLocal._text}</td>
<td>{item.Itinerary.EndDateLocal._text}</td>
</tr>
))}
</table>
null
}

Related

Reactjs click button handler with a parameter within a table parameter is always empty

I have a table which contains some table rows from a server each row have a button to edit the row data; I'm trying to call click handler function with a parameter of the Id of the record unfortunately its always empty; my jsx as bellow:
<table className="table table-bordered table-striped">
<thead>
<tr>
<th>Subscription #</th>
<th>Subscription Type</th>
<th>Subscription Period</th>
<th>Total Contract Amount</th>
<th>Subscription Start Date</th>
<th></th>
</tr>
</thead>
<tbody>
{subscriptions.map((d) => {
return (
<tr key={d.Id}>
<td>{d.subscriptionNumber}</td>
<td>{d.subscriptionType}</td>
<td>{d.subscriptionPeriod}</td>
<td>{d.totalContractAmount}</td>
<td>{d.subscriptionStartDate}</td>
<td>
<button
value={d.Id}
className="btn btn-primary"
onClick={(e) => handleEditSubscription(e.target.value)}
>
Edit
</button>
</td>
</tr>
);
})}
</tbody>
<tfoot></tfoot>
</table>
and my handler function as so :
function handleEditSubscription(subsId) {
console.log(subsId);
}
how to pass the parameter correctly here? thanks in advance.
Edit : I found the solution; the Id property must be id with small letter instead, what a silly mistake.
button doesn't have value property. Try the following code:
<button className="btn btn-primary"
onClick={(e)=> handleEditSubscription(d.Id)}
>
Edit
</button>

Render Modal for Dynamic Table in React

I have a dynamic table whose items I render through a list. The idea is that, on clicking the name of a row, a modal will open and that will print certain values retrieved from the backend server.
When I click on a specific person's name, the modal loads for all elements in the table. How do I fix this?
The rendered code for the table is as follows:-
<table className="table">
<thead>
<tr>
<th>S. NO.</th>
<th>NAME</th>
<th>ADDRESS</th>
<th>TELEPHONE</th>
<th>EMAIL</th>
<th>AGE</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.personData.map((pRow, idx) => (
<>
<PopUp hideModal={this.hideModal} show={this.state.show} id={siteRow.id} />
<tr key={pRow.id}>
<td>{idx + 1}</td>
<td> <a onClick={this.showModal}> {pRow.name} </a> </td>
<td>{pRow.address}</td>
<td>{pRow.phone}</td>
<td>{pRow.email}</td>
<td>{pRow.age}</td>
<td>
{" "}
<DeleteButton id={pRow.id} onDelete={this.onDelete} />{" "}
</td>
</tr>
</>
</tbody>
</table>
In the code for the table, the placement of the PopUp component is such because I want to pass the ID of the particular site to the modal.
This is the rendered code for the modal:-
showModal(e) {
this.setState({
show: true
});
}
hideModal(e) {
this.setState({
show:false
});
this.props.hideModal && this.props.hideModal(e);
}
render() {
if(!this.props.show){
return null;
}
return (
<>
<div>
The ID of the person is: {this.props.id}
<button type="button" className="btn theButton" onClick={this.hideModal}>CLOSE</button>
</div>
</>
);
}
This is very rudimentary code and I haven't added much CSS so this just opens up in the table itself. I want to change this but given the placement of the PopUp component and the fact that I want to pass the ID to the component, I'm not sure how to go about it.
The problem is that you have a series of Popups, but only a variable controlling their visibility. Consider replacing the show state as a simple visibility with a showId one, meant as the "id" of the Popup to be shown.
showModal(id) {
this.setState({
showId: id
});
}
hideModal(e) {
this.setState({
showId: null
});
this.props.hideModal && this.props.hideModal(e);
}
Then:
<table className="table">
<thead>
<tr>
<th>S. NO.</th>
<th>NAME</th>
<th>ADDRESS</th>
<th>TELEPHONE</th>
<th>EMAIL</th>
<th>AGE</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.personData.map((pRow, idx) => (
<>
<PopUp hideModal={this.hideModal} show={this.state.showId === pRow.id} id={siteRow.id} />
<tr key={pRow.id}>
<td>{idx + 1}</td>
<td> <a onClick={() => this.showModal(pRow.id)}> {pRow.name} </a> </td>
<td>{pRow.address}</td>
<td>{pRow.phone}</td>
<td>{pRow.email}</td>
<td>{pRow.age}</td>
<td>
{" "}
<DeleteButton id={pRow.id} onDelete={this.onDelete} />{" "}
</td>
</tr>
</>
</tbody>
</table>
I did not try the code, but I think it should work.

Getting 'Parse Error: Adjacent JSX elements must be wrapped in an enclosing tag' even when I use React.Fragment

I have a react component that renders a table. This is the code for render :-
<>
<table className="table">
<thead>
<tr>
<th>S. NO.</th>
<th>NAME</th>
<th>ADDRESS</th>
<th>TELEPHONE</th>
<th>EMAIL</th>
<th>AGE</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.personData.map((pRow, idx) => (
<tr key={pRow.id}>
<td>{idx + 1}</td>
<td data-toggle="modal" data-target="#myModal">{pRow.name}</td>
<td>{pRow.address}</td>
<td>{pRow.phone}</td>
<td>{pRow.email}</td>
<td>{pRow.age}</td>
<td>
{" "}
<DeleteButton
id={pRow.id}
onDelete={this.onDelete}
/>{" "}
</td>
</tr>
</tbody>
</table>
</>
I'm getting
Syntax error: Adjacent JSX elements must be wrapped in an enclosing
tag. Did you want a JSX fragment <>...? (123:4)
Here, line 123 is the line containing ''. What am I doing wrong here? I'm confused
Try this. Your map is not closed.
<>
<table className="table">
<thead>
<tr>
<th>S. NO.</th>
<th>NAME</th>
<th>ADDRESS</th>
<th>TELEPHONE</th>
<th>EMAIL</th>
<th>AGE</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.personData.map((pRow, idx) => (
<tr key={pRow.id}>
<td>{idx + 1}</td>
<td data-toggle="modal" data-target="#myModal">{pRow.name}</td>
<td>{pRow.address}</td>
<td>{pRow.phone}</td>
<td>{pRow.email}</td>
<td>{pRow.age}</td>
<td>
{" "}
<DeleteButton
id={pRow.id}
onDelete={this.onDelete}
/>{" "}
</td>
</tr>
))} // MISSING PROPER CLOSING HERE
</tbody>
</table>
</>
In this particular example, you just forgot to close the map method within <tbody>...</tbody>
It should be:
<tbody>
{this.state.personData.map((pRow, idx) => (
<tr key={pRow.id}>
<td>{idx + 1}</td>
<td data-toggle="modal" data-target="#myModal">{pRow.name}</td>
<td>{pRow.address}</td>
<td>{pRow.phone}</td>
<td>{pRow.email}</td>
<td>{pRow.age}</td>
<td>
{" "}
<DeleteButton
id={pRow.id}
onDelete={this.onDelete}
/>{" "}
</td>
</tr>
))}
</tbody>

Objects are not valid as a React child use an array instead

I'm getting "Objects are not valid as a React child" on this block:
<table className="table">
<thead>
<tr>
<th scope="col">Title</th>
<th scope="col">Genre</th>
<th scope="col">Stock</th>
<th scope="col">Rate</th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
{movies.filter(movie => (
<tr key={movie._id}>
<td>{movie.title}</td>
<td>{movie.genre.name}</td>
<td>{movie.numberInStock}</td>
<td>{movie.dailyRentalRate}</td>
<td>
<Like
onClick={() => this.handleLike(movie)}
liked={movie.liked}
/>
</td>
<td>
<button
onClick={() => this.handleDelete(movie._id)}
className="btn btn-danger m-2"
>
Delete
</button>
</td>
</tr>
))}
</tbody>
</table>
The exact error message reads: Error: Objects are not valid as a React child (found: object with keys {_id, title, genre, numberInStock, dailyRentalRate, publishDate, liked}). If you meant to render a collection of children, use an array instead.
No matter what I do to troubleshoot this the error won't go away. Can anyone explain ?
This:
<tbody>
{movies.map(movie => (
<tr key={movie._id}>
<td>{movie.title}</td>
<td>{movie.genre.name}</td>
<td>{movie.numberInStock}</td>
<td>{movie.dailyRentalRate}</td>
<td>
<Like
onClick={() => this.handleLike(movie)}
liked={movie.liked}
/>
</td>
<td>
<button
onClick={() => this.handleDelete(movie._id)}
className="btn btn-danger m-2"
>
Delete
</button>
</td>
</tr>
))}
</tbody>
Should look like this:
<tbody>
<MovieComponent
movie={movie}
likeOnCLick={this.handleLike(movie)}
/>
</tbody>
You're not filtering anything, so just use map(), and pass the results into a React.Component that you define elsewhere.
The filter method is used to select certain items of an array. It seems that you have confused this with the map method, which should work in this scenario.
filter: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
map: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

Having an issue with rendering table in a React component

I am trying to render a table inside a react component but having trouble aligning the rows with the header
render() {
console.log("Top Searches",this.props.topSearches)
return(
<div className="topsearches">
<table border="2" align="center">
<th> Search Term </th>
<th>Count </th>
{this.props.topSearches.map((top_search, index) => (
<tr>
{Object.keys(top_search).map(function(key) {
return <div>
<tbody>
<td align="center">{key} </td>
<td align="right">{top_search[key]}</td>
</tbody>
</div>
})}
</tr>
))}
</table>
</div>
)
}
This is the output i am getting
I assume, you are trying to achieve something like this.
I have edited this in codesandbox here.
https://codesandbox.io/s/sparkling-sound-yd1ih
return (
<div className="topsearches">
<table border="2" align="center">
<thead>
<th> Search Term </th>
<th>Count </th>
</thead>
<tbody>
{props.topSearches.map((top_search, index) =>
Object.keys(top_search).map((key, index) => {
return (
<tr>
<td>{key}</td>
<td>{top_search[key]}</td>
</tr>
);
})
)}
</tbody>
</table>
</div>
);
Modification I made to achieve this:
Added <thead>
Corrected <tbody> loop
Please let me know if you have any further questions!

Resources