4

So am trying to add sorting my react table component, i have wrote two functions one for sorting in ascending or and the other one for sorting in descending order and want it to fire on onClick but it just doesn't seems to work, i don't know what am doing wrong in the code. Here is my code:

import type { HTMLAttributes, FC } from 'react';
import React, { useState } from 'react';
import './Table.css';

export interface Props extends HTMLAttributes<HTMLHRElement> {
    colNames?: [];
    /** Data in JSON to feed the table */
    data?: JSON[];
}
/**
 * Component that serves as an table for ease of templating
 *
 * @return Table component
 */
export const Table: FC<Props> = ({ 
 data = [
    { id: 12, name: 'zebra', Age: 30 },
    { id: 2, name: 'Name2', Age: 30 },
    { id: 3, name: 'Name3', Age: 30 },
    { id: 4, name: 'Name4', Age: 30 },
],
colNames = ['id', 'name', 'Age'], }) => {
    const [sorted, setsorted] = useState(data);

    /** Function to sort ascending order */
    const ascOrder = (): void => {
        setsorted(sorted.sort((a: any, b: any) => a.id - b.id));
    };

    /** Function to sort descending order */
    const descOrder = (): void => {
        setsorted(sorted.sort((a: any, b: any) => b.id - a.id));
    };
    return (
        <div className="my-component-library-table-component-container">
            {data.length > 0 && (
                <table className="my-component-library-table-component" cellSpacing="0">
                    <thead className="header">
                        <tr>
                            {(colNames as any[]).map((headerItem, index) => (
                                <th key={index}>
                                    <span>{headerItem.toUpperCase()}</span>
                                    <button title={headerItem + 'ASC'} onClick={() => ascOrder}>
                                        ↑
                                    </button>
                                    <button title={headerItem + 'DESC'} onClick={() => descOrder}>
                                        ↓
                                    </button>
                                </th>
                            ))}
                        </tr>
                    </thead>
                    <tbody>
                        {Object.values(data).map((obj, index) => (
                            <tr key={index}>
                                {Object.values(obj).map((value, index2) => (
                                    <td key={index2}> {value} </td>
                                ))}
                            </tr>
                        ))}
                    </tbody>
                    <tfoot className="my-component-library-table-component-footer"></tfoot>
                </table>
            )}
        </div>
    );
};

Willow's Solution:

import type { HTMLAttributes, FC } from 'react';
import React, { useState } from 'react';
import './Table.css';

export interface Props extends HTMLAttributes<HTMLHRElement> {
    colNames?: [];
    /** Data in JSON to feed the table */
    data?: JSON[];
}
/**
 * Component that serves as an table for ease of templating
 *
 * @return Table component
 */
export const Table: FC<Props> = ({
    data = [
        { id: 12, name: 'zebra', Age: 30 },
        { id: 2, name: 'Name2', Age: 30 },
        { id: 3, name: 'Name3', Age: 30 },
        { id: 4, name: 'Name4', Age: 30 },
    ],
    colNames = ['id', 'name', 'Age'],
}) => {
    const [sorted, setsorted] = useState(data);

    /** Function to sort ascending order */
    const ascOrder = (): void => {
        setsorted(sorted.sort((a: any, b: any) => a.id - b.id));
    };

    /** Function to sort descending order */
    const descOrder = (): void => {
        setsorted(sorted.sort((a: any, b: any) => b.id - a.id));
    };
    return (
        <div className="my-component-library-table-component-container">
            {data.length > 0 && (
                <table className="my-component-library-table-component" cellSpacing="0">
                    <thead className="header">
                        <tr>
                            {(colNames as any[]).map((headerItem, index) => (
                                <th key={index}>
                                    <span>{headerItem.toUpperCase()}</span>
                                    <button title={headerItem + 'ASC'} onClick={ascOrder}>
                                        ↑
                                    </button>
                                    <button title={headerItem + 'DESC'} onClick={descOrder}>
                                        ↓
                                    </button>
                                </th>
                            ))}
                        </tr>
                    </thead>
                    <tbody>
                        {sorted.map((obj, index) => (
                            <tr key={index}>
                                {Object.values(obj).map((value, index2) => (
                                    <td key={index2}> {value} </td>
                                ))}
                            </tr>
                        ))}
                    </tbody>
                    <tfoot className="my-component-library-table-component-footer"></tfoot>
                </table>
            )}
        </div>
    );
};
6
  • What is the value of data ? If you could add that to your question it would be helpful :) Commented Feb 26, 2022 at 21:12
  • @Willow edited my question with the value of data and colName please have a look Commented Feb 26, 2022 at 21:58
  • If you update to the code in my answer, does the sorting by id work (and the other columns doesn't work), or do none of them still work? Commented Feb 27, 2022 at 0:14
  • Non of them work... @Willow Commented Feb 27, 2022 at 4:02
  • Does this answer your question? Sort an array of objects in React and render them Commented Feb 27, 2022 at 11:04

2 Answers 2

1
import type { HTMLAttributes, FC } from 'react';
import React, { useState } from 'react';
import './Table.css';

export interface Props extends HTMLAttributes<HTMLHRElement> {
    colNames?: [];
    /** Data in JSON to feed the table */
    data?: JSON[];
}
/**
 * Component that serves as an table for ease of templating
 *
 * @return Table component
 */
export const Table: FC<Props> = ({ 
 data = [
    { id: 12, name: 'zebra', Age: 30 },
    { id: 2, name: 'Name2', Age: 30 },
    { id: 3, name: 'Name3', Age: 30 },
    { id: 4, name: 'Name4', Age: 30 },
],
colNames = ['id', 'name', 'Age'], }) => {
    const [sorted, setSorted] = useState(data);

    /** Function to sort ascending order */
    const ascOrder = (): void => {
        setSorted([].concat(sorted).sort((a: any, b: any) => a.id - b.id));
    };

    /** Function to sort descending order */
    const descOrder = (): void => {
        setSorted([].concat(sorted).sort((a: any, b: any) => b.id - a.id));
    };
    return (
        <div className="my-component-library-table-component-container">
            {data.length > 0 && (
                <table className="my-component-library-table-component" cellSpacing="0">
                    <thead className="header">
                        <tr>
                            {(colNames as any[]).map((headerItem, index) => (
                                <th key={index}>
                                    <span>{headerItem.toUpperCase()}</span>
                                    <button title={headerItem + 'ASC'} onClick={() => ascOrder()}>
                                        ↑
                                    </button>
                                    <button title={headerItem + 'DESC'} onClick={() => descOrder()}>
                                        ↓
                                    </button>
                                </th>
                            ))}
                        </tr>
                    </thead>
                    <tbody>
                        {Object.values(sorted).map((obj, index) => (
                            <tr key={index}>
                                {Object.values(obj).map((value, index2) => (
                                    <td key={index2}> {value} </td>
                                ))}
                            </tr>
                        ))}
                    </tbody>
                    <tfoot className="my-component-library-table-component-footer"></tfoot>
                </table>
            )}
        </div>
    );
};

Please try the above code snippet instead ... You are actually not calling the sorting functions at all ... I added the parens to invoke them on click event ... That should work ... Let me know otherwise...

Sign up to request clarification or add additional context in comments.

4 Comments

no siddhart nothing
Updated my answer with fixes suggested at the Url in my comment ...
Still nothing @Siddharth Seth
Please try once more and let me know
0

Looks like you're not actually calling the ascOrder and descOrder functions. You are defining inline functions that return those functions. Instead, try this:

<button title={headerItem + 'ASC'} onClick={ascOrder}>
    ↑
</button>
<button title={headerItem + 'DESC'} onClick={descOrder}>
    ↓
</button>

EDIT: in addition, you are also mapping the original data instead of the sorted version. Try changing this:

{Object.values(data).map((obj, index) => (

to this:

{Object.values(sorted).map((obj, index) => (

EDIT: Shouldn't use Object.values if we want to keep the order!! Not sure how I missed that before.

Try this

{sorted.map(obj => (

EDIT: Maybe it's because you're using the indexes as keys. Instead of this:

                    <tbody>
                        {sorted.map((obj, index) => (
                            <tr key={index}>
                                {Object.values(obj).map((value, index2) => (
                                    <td key={index2}> {value} </td>
                                ))}
                            </tr>
                        ))}
                    </tbody>

Try this:

                    <tbody>
                        {sorted.map((obj) => (
                            <tr key={obj.id}>
                                {Object.values(obj).map((value, index2) => (
                                    <td key={index2}> {value} </td>
                                ))}
                            </tr>
                        ))}
                    </tbody>

7 Comments

nope does't work tried that first @Willow
Found another issue. Give that a try?
this seems to be the perfect answer but still even this doesn't work
Updated this again. Lmk if that helps
am sorry to say but still nothing....am updating my question with how my current code looks like after adding your solution have a look
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.