I am working on the table content which has 5 rows . few rows content description is same so I need to show only one row in this case and give expan button. when expand button is clicked it should show all the rows which has the same associated description. I am pasting the screenshot which I got as output .
In the above screenshot I've got the "-" button for all the rows which has same description. but I need only one "-"(collapse) button for "paytm" and one "-"button for "Paypal". and when they are clicked only one paytm, PayPal should be displayed.
let rows = [
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2020' },
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/04/2021' }
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/03/2020' }
},
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2021' }
},
{
id: { value: '' },
description: { value: 'Gpay' },
DueDate: { value: '04/03/2020' }
},
];
I am showing the table based on the lasted date and check if there exists any multiple same descriptions and putting them all in one object.
const descriptionSortedArray = rows.reduce((acc, current) => {
acc[current.description.value] = [
...(acc[current.description.value] || []),
current,
];
return acc;
}, {});
console.log(descriptionSortedArray);
and transforming the object based on latest date
const transformedRows = Object.keys(descriptionSortedArray).reduce(
(acc, current) => {
acc[current] = sortRowsByDate(descriptionSortedArray[current]);
return acc;
},
{}
);
// console.log(Object.keys(descriptionSortedArray));
console.log({ transformedRows });
and getting the key values for them by using object.keys and mapping over them.
x.[paytm:[], Gpay:[], PayPal :[]];
based on the inner array key length I am showing button (expand and collapse)if x[paytm]>1 ?show button: without button
code is below
import React, { Component } from 'react';
import './style.css';
export default class App extends React.Component {
render() {
let rows = [
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2020' },
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/04/2021' }
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/03/2020' }
},
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2021' }
},
{
id: { value: '' },
description: { value: 'Gpay' },
DueDate: { value: '04/03/2020' }
},
];
const descriptionSortedArray = rows.reduce((acc, current) => {
acc[current.description.value] = [
...(acc[current.description.value] || []),
current,
];
return acc;
}, {});
console.log(descriptionSortedArray);
const sortRowsByDate = (rows) =>
rows.sort(
(a, b) => new Date(b.DueDate.value) - new Date(a.DueDate.value)
);
const transformedRows = Object.keys(descriptionSortedArray).reduce(
(acc, current) => {
acc[current] = sortRowsByDate(descriptionSortedArray[current]);
return acc;
},
{}
);
// console.log(Object.keys(descriptionSortedArray));
console.log({ transformedRows });
return (
<div>
<table>
<tr>
<th>id</th>
<th>description</th>
<th>duedate</th>
<th></th>
</tr>
{Object.keys(transformedRows).map((rowKey) => {
// console.log("rowKey===", rowKey)
// console.log(transformedRows[rowKey])
return (
<tbody>
{transformedRows[rowKey].length > 1
? transformedRows[rowKey].map((obj) => (
<tr>
<td>{obj.id.value}</td>
<td>{obj.description.value}</td>
<td>{obj.DueDate.value}</td>
<td>{<button>-</button>}</td>
</tr>
))
: transformedRows[rowKey].map((obj) => (
<tr>
<td>{obj.id.value}</td>
<td>{obj.description.value}</td>
<td>{obj.DueDate.value}</td>
<td></td>
</tr>
))}
</tbody>
);
})}
</table>
</div>
);
}
}
Please help in this. I need to show only one collapse button for the rows having same description(paytm is repeated show them only in one row give "expand" and "collapse" button). when even button is clicked it should be toggled. Please help
I am working on the table content which has 5 rows . few rows content description is same so I need to show only one row in this case and give expan button. when expand button is clicked it should show all the rows which has the same associated description. I am pasting the screenshot which I got as output .
In the above screenshot I've got the "-" button for all the rows which has same description. but I need only one "-"(collapse) button for "paytm" and one "-"button for "Paypal". and when they are clicked only one paytm, PayPal should be displayed.
let rows = [
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2020' },
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/04/2021' }
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/03/2020' }
},
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2021' }
},
{
id: { value: '' },
description: { value: 'Gpay' },
DueDate: { value: '04/03/2020' }
},
];
I am showing the table based on the lasted date and check if there exists any multiple same descriptions and putting them all in one object.
const descriptionSortedArray = rows.reduce((acc, current) => {
acc[current.description.value] = [
...(acc[current.description.value] || []),
current,
];
return acc;
}, {});
console.log(descriptionSortedArray);
and transforming the object based on latest date
const transformedRows = Object.keys(descriptionSortedArray).reduce(
(acc, current) => {
acc[current] = sortRowsByDate(descriptionSortedArray[current]);
return acc;
},
{}
);
// console.log(Object.keys(descriptionSortedArray));
console.log({ transformedRows });
and getting the key values for them by using object.keys and mapping over them.
x.[paytm:[], Gpay:[], PayPal :[]];
based on the inner array key length I am showing button (expand and collapse)if x[paytm]>1 ?show button: without button
code is below
import React, { Component } from 'react';
import './style.css';
export default class App extends React.Component {
render() {
let rows = [
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2020' },
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/04/2021' }
},
{
id: { value: '' },
description: { value: 'paypal' },
DueDate: { value: '04/03/2020' }
},
{
id: { value: '' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2021' }
},
{
id: { value: '' },
description: { value: 'Gpay' },
DueDate: { value: '04/03/2020' }
},
];
const descriptionSortedArray = rows.reduce((acc, current) => {
acc[current.description.value] = [
...(acc[current.description.value] || []),
current,
];
return acc;
}, {});
console.log(descriptionSortedArray);
const sortRowsByDate = (rows) =>
rows.sort(
(a, b) => new Date(b.DueDate.value) - new Date(a.DueDate.value)
);
const transformedRows = Object.keys(descriptionSortedArray).reduce(
(acc, current) => {
acc[current] = sortRowsByDate(descriptionSortedArray[current]);
return acc;
},
{}
);
// console.log(Object.keys(descriptionSortedArray));
console.log({ transformedRows });
return (
<div>
<table>
<tr>
<th>id</th>
<th>description</th>
<th>duedate</th>
<th></th>
</tr>
{Object.keys(transformedRows).map((rowKey) => {
// console.log("rowKey===", rowKey)
// console.log(transformedRows[rowKey])
return (
<tbody>
{transformedRows[rowKey].length > 1
? transformedRows[rowKey].map((obj) => (
<tr>
<td>{obj.id.value}</td>
<td>{obj.description.value}</td>
<td>{obj.DueDate.value}</td>
<td>{<button>-</button>}</td>
</tr>
))
: transformedRows[rowKey].map((obj) => (
<tr>
<td>{obj.id.value}</td>
<td>{obj.description.value}</td>
<td>{obj.DueDate.value}</td>
<td></td>
</tr>
))}
</tbody>
);
})}
</table>
</div>
);
}
}
Please help in this. I need to show only one collapse button for the rows having same description(paytm is repeated show them only in one row give "expand" and "collapse" button). when even button is clicked it should be toggled. Please help
Share Improve this question edited Feb 4, 2022 at 7:55 Amila Senadheera 13.3k16 gold badges29 silver badges46 bronze badges asked Feb 4, 2022 at 7:53 SathishSathish 681 gold badge2 silver badges9 bronze badges 5- 1 stackblitz./edit/react-6dt9gp?file=src%2FApp.js I've implemented an exapmle here, if it solves your problem let me to post it as answer. – Saeed Shamloo Commented Feb 4, 2022 at 8:37
- @Saeed Shamloo it works for me. It is appreciated if you can help me with the need of both paytm and paypal es under same group so there should not be any "border" between them when expanded. – Sathish Commented Feb 4, 2022 at 11:07
- I didn't understand exactly what you mean, but I made some changes in the example. please check it out. – Saeed Shamloo Commented Feb 4, 2022 at 12:07
- thanks for trying, but still when I clicked on expand paytm, paypal rows also are loading. previous one was fine. It was almost full filling my requirement . I will try for border collapse. Please upload previous answer. – Sathish Commented Feb 4, 2022 at 14:05
- I reverted to previous one. – Saeed Shamloo Commented Feb 4, 2022 at 14:14
2 Answers
Reset to default 3You can keep another field called visible along with your data array and toggle its value when clicked on the button.
- Define a state to store the
transformedRows
state = {
transformedRows: {}
};
- Do the transformation like below in
ponentDidMount
.
ponentDidMount = () => {
const descriptionSortedArray = rows.reduce((acc, current) => {
acc[current.description.value] = {
...acc[current.description.value],
data: [...(acc[current.description.value]?.["data"] ?? []), current],
visible: false
};
return acc;
}, {});
const sortRowsByDate = (rows) =>
rows.sort(
(a, b) => new Date(b.DueDate.value) - new Date(a.DueDate.value.data)
);
const transformedRows = Object.keys(descriptionSortedArray).reduce(
(acc, current) => {
acc[current] = {
...descriptionSortedArray[current],
data: sortRowsByDate(descriptionSortedArray[current]["data"])
};
return acc;
},
{}
);
this.setState({ transformedRows });
};
- Toggle the visible state when clicking on the button.
handleToggle = (entry, visibility) => {
this.setState((prevState) => {
return {
...prevState,
transformedRows: Object.fromEntries(
Object.entries(prevState.transformedRows).map(([key, value]) => {
if (key === entry) {
return [key, { ...value, visible: visibility }];
} else {
return [key, value];
}
})
)
};
});
};
- Render rows as below.
<tbody>
{Object.entries(transformedRows).map(([key, { data, visible }]) => {
if (data.length > 1) {
return data.map((item, index) => (
<tr>
{(index === 0 || (index >= 1 && visible)) && (
<>
<td>{item.id.value}</td>
<td>{item.description.value}</td>
<td>{item.DueDate.value}</td>
</>
)}
{index === 0 && (
<td>
{
<button
onClick={() => {
this.handleToggle(key, !visible);
}}
>
toggle
</button>
}
</td>
)}
</tr>
));
} else {
return data.map(item => (
<tr>
<td>{item.id.value}</td>
<td>{item.description.value}</td>
<td>{item.DueDate.value}</td>
</tr>
));
}
})}
</tbody>
Create an accordion ponent as follow:
React accordion
Then use it as follow:
return (
<div>
<table>
<thead>
<tr>
<th>id</th>
<th>description</th>
<th>duedate</th>
<th></th>
</tr>
</thead>
{Object.keys(transformedRows).map((rowKey) => {
// console.log("rowKey===", rowKey)
// console.log(transformedRows[rowKey])
console.log(rowKey);
return (
<tbody key={rowKey}>
{transformedRows[rowKey].length > 1 ? (
<tr>
<td colSpan="4">
<Accordion label={rowKey}>
{transformedRows[rowKey].map((obj) => (
<div key={obj.id.value}>
<span>{obj.id.value}</span>
<span>{obj.description.value}</span>
<span>{obj.DueDate.value}</span>
<span>{<button>-</button>}</span>
</div>
))}
</Accordion>
</td>
</tr>
) : (
transformedRows[rowKey].map((obj) => (
<tr key={obj.id.value}>
<td>{obj.id.value}</td>
<td>{obj.description.value}</td>
<td>{obj.DueDate.value}</td>
<td></td>
</tr>
))
)}
</tbody>
);
})}
</table>
</div>
);
Full code:
let rows = [
{
id: { value: '1' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2020' },
},
{
id: { value: '2' },
description: { value: 'paypal' },
DueDate: { value: '04/04/2021' },
},
{
id: { value: '3' },
description: { value: 'paypal' },
DueDate: { value: '04/03/2020' },
},
{
id: { value: '4' },
description: { value: 'Paytm' },
DueDate: { value: '04/03/2021' },
},
{
id: { value: '5' },
description: { value: 'Gpay' },
DueDate: { value: '04/03/2020' },
},
];
const descriptionSortedArray = rows.reduce((acc, current) => {
acc[current.description.value] = [...(acc[current.description.value] || []), current];
return acc;
}, {});
console.log(descriptionSortedArray);
const sortRowsByDate = (rows) =>
rows.sort((a, b) => new Date(b.DueDate.value) - new Date(a.DueDate.value));
const transformedRows = Object.keys(descriptionSortedArray).reduce((acc, current) => {
acc[current] = sortRowsByDate(descriptionSortedArray[current]);
return acc;
}, {});
return (
<div>
<table>
<thead>
<tr>
<th>id</th>
<th>description</th>
<th>duedate</th>
<th></th>
</tr>
</thead>
{Object.keys(transformedRows).map((rowKey) => {
// console.log("rowKey===", rowKey)
// console.log(transformedRows[rowKey])
console.log(rowKey);
return (
<tbody key={rowKey}>
{transformedRows[rowKey].length > 1 ? (
<tr>
<td colSpan="4">
<Accordion label={rowKey}>
{transformedRows[rowKey].map((obj) => (
<div key={obj.id.value}>
<span>{obj.id.value}</span>
<span>{obj.description.value}</span>
<span>{obj.DueDate.value}</span>
<span>{<button>-</button>}</span>
</div>
))}
</Accordion>
</td>
</tr>
) : (
transformedRows[rowKey].map((obj) => (
<tr key={obj.id.value}>
<td>{obj.id.value}</td>
<td>{obj.description.value}</td>
<td>{obj.DueDate.value}</td>
<td></td>
</tr>
))
)}
</tbody>
);
})}
</table>
</div>
);