Read more and read less for paragraph in react - javascript

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

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>
))}

Suggestion to refactor code into simple way -React

I have multiple with the same class name and method with different parameter
i want to refactor the below code to a simpler way any suggestion would be helpful.
<table class="greyGridTable">
<tbody>
<tr>
<td>AA</td>
<td className = 'table-container'>{formatDate(someMethod1(param1,a)}</td>
</tr>
<tr>
<td>BB</td>
<td className = 'table-container'>{formatDate(someMethod1(param1,b)}</td>
</tr>
<tr>
<td>CC</td>
<td className = 'table-container'>{formatDate(someMethod1(param1,c)}</td>
</tr>
</tbody>
</table>
I want to refactor the code with the same component.
I hope this would be helpful. thanks
export const TableItems = ({data}) => {
return (
<>
{data.map(item => (
<tr>
<td>{item.name}</td>
<td className='table-container'> {item?.symbol} {formatDate(someMethod1(param1,a)}</td>
</tr>
))}
</>
)
}
const data = [
{
name: AA,
},
{
name: BB,
},
{
name: CC,
symbol: '£'
}
]
<table class="greyGridTable">
<tbody>
<TableItems data={data} />
</tbody>
</table>
Try to use an array instead. Having reusable components in an array is easy to maintain, expand and read. Definitely a good practice.
let tableItems = [{name:"AA",date:new Date()},.....]
return (
<table class="greyGridTable">
<tbody>
{tableItems.map((item,index)=>{
return(
<tr>
<td>{item.date}</td>
<td className = 'table-container'>{item.date}</td>
</tr>
)
})}
</tbody>
</table>
)

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.

sort table with multiple related rows per entity

How should I solve the following problem> I have data about each entity in multiple, related rows in a table (I know using table is obsolate, I should use divs, but I am fine with tables. If div is necessary, I will change.)
I put fresh data into the cells every x seconds based on their ids using jQuery. I need a javascript function or something that will allow me to reorder the table respecting the multiple cohorent rows. I am open to any other approach.
(PHP part added just for understanding.)
<table>
<?php
foreach($members as $member)
{
//data for this member starts here
echo"<tr>
<td>John</td>
<td>score:1000</td>
<td>MAX score:2000</td>
</tr>
<tr>
<td>somevalue:3000</td>
<td>another value:4000</td>
<td>another value:4000</td>
</tr>
<tr>
<td collspan=‘3'>This is a row for separate the members</td>
</tr>
";
//data for this member ends here
}
?>
</table>
For example I would like to sort based on the score. The sorting should carry the row containing the “somevalue” and the separator row as well to the new “position”.
I am going to go out on a limb here and give you one option. Put the data into single rows in a set of div and span to simulate the markup of table rows and cells. Note you will have to style these to better emulate that. (perhaps bootstrap row etc. but I will leave that to you), key here is the sort.
Here to simplify the logic I put a numeric value in a data attribute on each row, then sort rows by that.
Note: assumptions made of single tbody, has that, single sort value, numeric data value etc.
IF you wanted you could put multiple 'tbody' with data attributes and sort those - I will leave that exercise to you but the flow my get slow on large sets of data.
NOTE: call the sort whenever you render or add. You could also avoid the subsequent sorts, simply inserting rows after the one before.
Example to insert (might be better but enough to start with)
var $newRow = $('<tr data-sortdata="5"><td>putalldivs in here<td></tr>');
var rowToInsertBefore = $('#mytable').find('tr').filter(function() {
return $(this).data('sortdata') >= $newRow.data('sortdata');
}).get(0);
if (typeof rowToInsertBefore === 'undefined') {
$('#mytable').find('tbody').append($newRow);
} else {
$newRow.insertBefore(rowToInsertBefore);
}
The bulk of the code to sort:
function sortTable(table, order, item) {
var asc = order === 'asc',
tbody = table.find('tbody'),
sd = item ? item : "sortdata";
tbody.find('tr').sort(function(a, b) {
var sA = 1 * $(a).data(sd);
var sB = 1 * $(b).data(sd);
if (asc) {
return (sA < sB) ? -1 : (1 * sA > sB) ? 1 : 0;
} else {
return (sB < sA) ? -1 : (sB > sA) ? 1 : 0;
}
}).appendTo(tbody);
}
sortTable($('#mytable'), 'asc', 'sortdata');
table {
border-collapse: collapse;
}
tr {
border: solid 1px lime;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="mytable">
<thead>
<tr>
<th>Col1</th>
<th>Col2</th>
<th>Col3</th>
</tr>
</thead>
<tbody>
<tr data-sortdata="3000">
<td>
<div>
<span>John</span>
<span>score:1000</span>
<span>MAX score:2000</span>
</div>
<div>
<span>somevalue:3000</span>
<span>another value:4000</span>
<span>another value:4000</span>
</div>
<div>
<span>This is a row for separate the members</span>
</div>
</td>
</tr>
<tr data-sortdata="5000">
<td>
<div>
<span>Brenda</span>
<span>score:3000</span>
<span>MAX score:2000</span>
</div>
<div>
<span>somevalue:5000</span>
<span>another value:4000</span>
<span>another value:4000</span>
</div>
<div>
<span>This is a row for separate the members</span>
</div>
</td>
</tr>
<tr data-sortdata="1000">
<td>
<div>
<span>Harry</span>
<span>score:1000</span>
<span>MAX score:500</span>
</div>
<div>
<span>somevalue:1000</span>
<span>another value:4000</span>
<span>another value:4000</span>
</div>
<div>
<span>This is a row for separate the members</span>
</div>
</td>
</tr>
<tr data-sortdata="1000">
<td>
<div>
<span>Brenda1</span>
<span>score:3000</span>
<span>MAX score:2000</span>
</div>
<div>
<span>somevalue:1000</span>
<span>another value:4000</span>
<span>another value:4000</span>
</div>
<div>
<span>This is a row for separate the members</span>
</div>
</td>
</tr>
</tbody>
</table>
Finally I figured out, but I think I will rework Mark Schultheiss’s solution and use that one. More elegant..
EDITED: added some tweeks:
1, if you have more tables in webpage, you have to add class identifier..
2, If you have also non numeric stuff in the cell, like text, etc but you want to sort based on the numeric value part=> put a div class in cell surrounding the number..
<html>
<head>
<script src="/js/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("#sort").click(function () {
var $tBodies = $('.klantabla tbody').sort(function(b, a){
var aVal = +($(a).find('tr:nth-child(1) td:nth-child(3) div.num').text().trim() || 0);
var bVal = +($(b).find('tr:nth-child(1) td:nth-child(3) div.num').text().trim() || 0);
return aVal - bVal;
});
$(‘.klantabla').append($tBodies);
});
});
</script>
</head>
<body>
<input type="button" value="sort by 3rd row, 3rd column " id="sort" />
<table border=‘1' class=‘klantabla'>
<thead>
<tr>
<th>Header 1</th>
<th>Header 2</th>
<th>Header 3</th>
</tr>
</thead>
<tbody class="member-1">
<tr>
<td>3 member1</td>
<td>1</td>
<td><div class=’num’>SOME SCORE 9</div></td>
</tr>
<tr>
<td>2 member1</td>
<td>2</td>
<td>5</td>
</tr>
<tr>
<td>1 member1</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td colspan="3">SAPARTOR for member1</td>
</tr>
</tbody>
<tbody class="member-3">
<tr>
<td>3 member3</td>
<td>3</td>
<td>11111111115</td>
</tr>
<tr>
<td>2 member3</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>1 member3</td>
<td>2</td>
<td>9</td>
</tr>
<tr>
<td colspan="3">SEPARATOR for member3</td>
</tr>
</tbody>
<tbody class="member-2">
<tr>
<td>3 member2</td>
<td>2</td>
<td>5</td>
</tr>
<tr>
<td>2 member2</td>
<td>7</td>
<td>5</td>
</tr>
<tr>
<td>1 member2</td>
<td>2</td>
<td>999</td>
</tr>
<tr>
<td colspan="3">SEPARATOR for member2</td>
</tr>
</tbody>
</table>
</body>
</html>

Categories