最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to expand and collapse the table rows in plain react js. Show only one row if the description of the row is mul

programmeradmin6浏览0评论

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
Add a ment  | 

2 Answers 2

Reset to default 3

You can keep another field called visible along with your data array and toggle its value when clicked on the button.

  1. Define a state to store the transformedRows
  state = {
    transformedRows: {}
  };
  1. 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 });
  };
  1. 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];
            }
          })
        )
      };
    });
  };
  1. 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>
);

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论