How to truncate text in cell in Bootstrap Table in React? - javascript

I have a Bootstrap Table component, and one cell within that table is a URL. The URL can be long, so I'd like to automatically truncate it with an ellipsis to fit within the cell.
Here's an example of what the issue looks like.
You can see the URL and the Table exceed the width of the Card component they're in.
I managed to come up with a fix, but it's not ideal. Here's my code:
<div>
<Accordion>
{this.state.previous_entries.map(pe =>
<Card key={pe.listing.id}>
<CustomToggle eventKey={pe.listing.id}>{[formatAddress(pe), pe.listing.createdAt]}</CustomToggle>
<Accordion.Collapse eventKey={pe.listing.id}>
<Card.Body>
<Table bordered style={{marginBottom: 0}}>
<tbody>
<tr>
<td className="bg-light">URL</td>
<td colSpan="3">
<!-- THIS PART -->
<a href={pe.listing.url}>
<span style={{textOverflow: "ellipsis", overflow: "hidden", whiteSpace:"nowrap", position: "fixed", maxWidth: "14%"}}>{ pe.listing.url }</span>
</a>
</td>
</tr>
<tr>
<td className="bg-light">Monthly Rent</td>
<td>{ pe.listing.monthly_rent ? pe.listing.monthly_rent + "万円" : "N/A" }</td>
<td className="bg-light">礼金</td>
<td>{ pe.listing.reikin !== null ? (pe.listing.reikin !== 0 ? pe.listing.reikin + "ヶ月" : pe.listing.reikin) : "N/A" }</td>
</tr>
<tr>
<td className="bg-light">敷金</td>
<td>{ pe.listing.security_deposit !== null ? (pe.listing.security_deposit !== 0 ? pe.listing.security_deposit + "ヶ月" : pe.listing.security_deposit) : "N/A" }</td>
<td className="bg-light">面積</td>
<td>{ pe.listing.square_m ? pe.listing.square_m + "m²" : "N/A" }</td>
</tr>
<tr>
<td className="bg-light">Closest Station</td>
<td>{ pe.listing.closest_station ? pe.listing.closest_station : "N/A" }</td>
<td className="bg-light">Walking Time</td>
<td>{ pe.listing.walking_time ? pe.listing.walking_time + "分" : "N/A" }</td>
</tr>
<tr>
<td className="bg-light">Availability</td>
<td>{ pe.listing.availability ? pe.listing.availability : "N/A" }</td>
<td className="bg-light">Interest</td>
<td>{ pe.property.interest ? pe.property.interest : "N/A" }</td>
</tr>
</tbody>
</Table>
</Card.Body>
</Accordion.Collapse>
</Card>
)}
</Accordion>
</div>
My 'fix' was adding the maxWidth: "14%" style to the span containing the URL. But this doesn't work great in all cases, depending on the size of the window. Which makes sense because it's a static value.
Here's what my 'fix' looks like.
Does someone know a better way of automatically truncating the URL so that the Table doesn't exceed the Card?

This approach is more flexible when it comes to various screen sizes, as you are not specifying a width for the text-overflow.
table {
table-layout: fixed;
width: 100%;
}
td>a {
display: block;
text-overflow: ellipsis;
overflow: hidden;
max-width: 100%;
}
td>a>span {
white-space: nowrap;
}
<div>
<Accordion>
{this.state.previous_entries.map(pe =>
<Card key={pe.listing.id}>
<CustomToggle eventKey={pe.listing.id}>{[formatAddress(pe), pe.listing.createdAt]}</CustomToggle>
<Accordion.Collapse eventKey={pe.listing.id}>
<Card.Body>
<Table bordered style={{marginBottom: 0}}>
<tbody>
<tr>
<td className="bg-light">URL</td>
<td colSpan="3">
<!-- THIS PART -->
<a href={pe.listing.url}>
<span style={{textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "nowrap", position: "fixed", maxWidth: "14%"}}>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.</span>
</a>
</td>
</tr>
<tr>
<td className="bg-light">Monthly Rent</td>
<td>{ pe.listing.monthly_rent ? pe.listing.monthly_rent + "万円" : "N/A" }</td>
<td className="bg-light">礼金</td>
<td>{ pe.listing.reikin !== null ? (pe.listing.reikin !== 0 ? pe.listing.reikin + "ヶ月" : pe.listing.reikin) : "N/A" }</td>
</tr>
<tr>
<td className="bg-light">敷金</td>
<td>{ pe.listing.security_deposit !== null ? (pe.listing.security_deposit !== 0 ? pe.listing.security_deposit + "ヶ月" : pe.listing.security_deposit) : "N/A" }</td>
<td className="bg-light">面積</td>
<td>{ pe.listing.square_m ? pe.listing.square_m + "m²" : "N/A" }</td>
</tr>
<tr>
<td className="bg-light">Closest Station</td>
<td>{ pe.listing.closest_station ? pe.listing.closest_station : "N/A" }</td>
<td className="bg-light">Walking Time</td>
<td>{ pe.listing.walking_time ? pe.listing.walking_time + "分" : "N/A" }</td>
</tr>
<tr>
<td className="bg-light">Availability</td>
<td>{ pe.listing.availability ? pe.listing.availability : "N/A" }</td>
<td className="bg-light">Interest</td>
<td>{ pe.property.interest ? pe.property.interest : "N/A" }</td>
</tr>
</tbody>
</Table>
</Card.Body>
</Accordion.Collapse>
</Card>
)}
</Accordion>
</div>

Related

How can I change the background color on reactstrap Table?

The table's thead's color is grey now. and I want to change the color of thead to blue. Is there a way to change the color using reactstrap? I tried putting bgcolor='~~' in the thead tag, but it didn't work. (I think it only works on pure html tag - table)
<Table className='table-fix' responsive bordered >
<thead bgcolor='#12487E'>
<tr >
<th style={{ width: '20%' }}>one</th>
<th style={{ width: '25%' }}>two</th>
<th style={{ width: '55%' }}>three</th>
</tr>
</thead>
<tbody>
{
curDoc.list.map((e, i) => {
return (<tr key={i}>
<td className='text-center'>{curDoc.date}</td>
<td className='text-center'>{curDoc.docFlag}</td>
<td data-bs-toggle="tooltip" data-bs-placement="top" title={e}>{e}</td>
</tr>)
})
}
</tbody>
</Table>

Read more and read less for paragraph in react

I want to add read-more and read-less functions to a paragraph using class
I am rendering components like this
<table border="1">
<tbody>
{data
? Object.keys(data).map((item) => {
return (
<tr key={"tr" + item}>
{data[item]
? Object.keys(data[item]).map((key) => {
return (
<td
key={"td" + key}
className={key === "description" && "read-more"}
>
{data[item][key]}
</td>
);
})
: null}
</tr>
);
})
: null}
</tbody>
</table>
And the output is this
<table border="1">
<tbody>
<tr>
<td>New expense</td>
<td>default</td>
<td>10000</td>
<td class="read-more">
Long paragraph..
</td>
</tr>
<tr>
<td>New New exp</td>
<td>default</td>
<td>123</td>
<td class="read-more">
Long paragraph.. not displaying due to stack overflow too much code thing
</td>
</tr>
</tbody>
</table>
So I am making many paragraphs using objects and this runs in other components too
So all I want is a function in which it for each or use any loop to get elements class named read-more and add function to it in which it creates an anchor tag for read-more and read-less by only using a class to p tag
Please solve my problem. Thanks

how to generate unique id for table cells using map

I want to set a unique id for each MenuItem, but I don't know how to do this with map() function nested in another one
<table className={classes.table}>
<thead>
<tr>
<td />
{sit.sit.map(sit => (
<td className={classes.sitCell} align="center" key={sit}>
{sit}
</td>
))}
</tr>
</thead>
<tbody>
{sit.row.map(row => (
<tr key={row}>
<td className={classes.rowCell} align="left">
{row}
</td>
{sit.sit.map(sit => (
<td className={classes.sit} key={(id = id + 1)}>
<MenuItem
id={sitId}
onClick={handleSitClick}
disabled={selected}
className={classes.sit}
/>
</td>
))}
</tr>
))}
</tbody>
</table>
Provided code looks fine for me. You can use uuid or any other similar package to generate keys.
Your question is not fully clear i think its may be help you .
<table className={classes.table }>
<thead>
<tr>
<td></td>
{
sit.sit.map((sit) => (<td className={classes.sitCell} align='center' key={sit}>{sit}</td>))
}
</tr>
</thead>
<tbody>
{
sit.row.map((row,index )=> (
<tr key={index}>
<td className={classes.rowCell} align='left'>{row}</td>
{
sit.sit.map((sit) => (<td className={classes.sit} key={id = id+1}><MenuItem id={sitId} onClick={handleSitClick} disabled={selected} className={classes.sit}></MenuItem></td>))
}
</tr>
))
}
</tbody>
</table>
you can just add (row,index) like this
Ideally you need to use a key which is some kind of unique id from your api response. Check your api response data structure, if it has an unique id, then use it. Else use the map array index.
Like this
<table className={classes.table}>
<thead>
<tr>
<td></td>
{
sit.sit.map((sit) => (<td className={classes.sitCell} align='center' key={sit}>{sit}</td>))
}
</tr>
</thead>
<tbody>
{
sit.row.map(row => (
<tr key={row}>
<td className={classes.rowCell} align='left'>{row}</td>
{
sit.sit.map((sit, index) => (<td className={classes.sit} key={index}><MenuItem id={index} onClick={handleSitClick} disabled={selected} className={classes.sit}></MenuItem></td>))
}
</tr>
))
}
</tbody>
</table>

React.js- Dynamic table with rowspan

I am trying to create a dynamic table, using this example- Dynamic & Complex rowspan in HTML table
I am trying to replicate the similar thing in react.js
I have put a closing tr tag in conditional rendering if the index is 0.
However, it gives me ' Expected corresponding JSX closing tag for <>'
The state 'data' object which I got from back-end is something like -
{
"100": [
"ABC"
],
"101": [
"123",
"DEF",
"XYZ",
"456",
"657",
"1234",
"4564",
"vdfgx",
"vcegefgg",
"g544"
]
}
I have written following code in component to create dynamic table.
<table>
<thead>
<tr>
<th>Code</th>
<th>Reason</th>
</tr>
</thead>
<tbody>
{Object.keys(this.state.data).map(
(error_code, i) => {
return (
<React.Fragment>
<tr>
<td
rowSpan={
this.state.data[
error_code
].length
}
key={i}
>
{error_code}
</td>
{this.state.data[
error_code
].map((error_description, index) => (
<React.Fragment>
{index === 0 ? (
<React.Fragment>
<td
key={index}
rowSpan="1"
>
{error_description}
</td>
</tr> //<--- HERE
</React.Fragment>
) : (
<tr>
<td
key={index}
rowSpan="1"
>
{error_description}
</td>
</tr>
)}
</React.Fragment>
))}
</React.Fragment>
);
}
)}
</tbody>
</table>
I want the final output something like -
<tbody>
<tr>
<td rowspan="1">100</td>
<td rowspan="1">ABC</td>
</tr>
<tr>
<td rowspan="10">101</td>
<td rowspan="1">123</td>
</tr>
<tr>
<td rowspan="1">DEF</td>
</tr>
<tr>
<td rowspan="1">XYZ</td>
</tr>
<tr>
<td rowspan="1">456</td>
</tr>
.....
</tbody>
Could anyone please guide me the correct way to achieve the desired output ?
JSX, like XML, requires proper nesting <><tr>...</tr></> and does not support overlapping tags like <><tr></></tr>. You need to structure your code in a way to preserve proper nesting:
<tbody>
{Object.keys(this.state.data).map((error_code, i) => {
return this.state.data[error_code].map((error_description, index) =>
index === 0 ? (
<tr>
<td rowSpan={this.state.data[error_code].length} key={i}>
{error_code}
</td>
<td key={index} rowSpan="1">
{error_description}
</td>
</tr>
) : (
<tr>
<td key={index} rowSpan="1">
{error_description}
</td>
</tr>
)
)
})}
</tbody>
JSX does not generate a string. It generates a tree-like structure built out of function calls and Objects. Any <tag></tag> translates into a function call, that's why your code is invalid.
You need to rethink this component.
Split the data processing and decision making into a separate function that does only that and returns the final data to be rendered. Then loop/map through it in render and return the elements structure.

Conditional rendering in ReactJS between button and normal text

I have one object array say defect and now if the status of the defect is open then it should show as button and it should read close the defect and if it is closed, then instead as button it should just mention as closed.
So, here statusRender is the issue and is now working as expected in the last column. Cant figure out what I am missing. Any leads?
render() {
if (defect.defect_status == 'open') {
statusRender = <button key={index} data-id={defect.id} onClick={() => this.showAlert(defect.defect_id)}>{defect.defect_status}</button>;
} else {
statusRender = { defect.defect_status };
}
return (
<div>
<table className="table table-bordered table-hover">
<thead>
<tr>
<th>Defect ID</th>
<th>Category</th>
<th>Description</th>
<th>Priority</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{this.state.defectList.map((defect, index) => {
return (
<tr key={index}>
<td> {defect.defect_id} </td>
<td>{defect.defect_category}</td>
<td>{defect.defect_description}</td>
<td>{defect.defect_priority}</td>
<td> {statusRender}
</td>
</tr>
);
})
}
</tbody>
</table>
</div>
)
}
it is a scope issue you cannot declare defect outside of the map function
{this.state.defectList.map((defect,index) => {
return (
<tr key={index}>
<td> {defect.defect_id} </td>
<td>{defect.defect_category}</td>
<td>{ defect.defect_description}</td>
<td>{ defect.defect_priority}</td>
<td>
{
defect.defect_status === 'open'
? <button key={index} data-id={defect.id} onClick = {() => this.showAlert(defect.defect_id)}>{defect.defect_status}</button>;
: defect.defect_status;
}
</td>
</tr>
);
})
}
Thanks to user1095118 removing the semi colons did the job. I was missing the correctness of the curly braces which solved the issue
{
defect.defect_status == 'open'
?<button key={index} data-id={defect.id} onClick = {() => this.showAlert(defect.defect_id)}>{defect.defect_status}</button> : defect.defect_status
}
If you just need to access status string instead of the button maybe you should remove brackets in your if else statement
render() {
if(defect.defect_status=='open') {
statusRender = <button key={index} data-id={defect.id} onClick = {() => this.showAlert(defect.defect_id)}>{defect.defect_status}</button>;
} else {
// No brackets here ?
statusRender = defect.defect_status;
}
return (
<div>
<table className="table table-bordered table-hover">
<thead>
<tr>
<th>Defect ID</th>
<th>Category</th>
<th>Description</th>
<th>Priority</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{this.state.defectList.map((defect,index) =>{
return(
<tr key={index}>
<td> {defect.defect_id} </td>
<td>{defect.defect_category}</td>
<td>{ defect.defect_description}</td>
<td>{ defect.defect_priority}</td>
<td> {statusRender}
</td>
</tr>
);
})
}
</tbody>
</table>
</div>
)
}
}

Categories