Home > Net >  render custom component on table based on the value of my data object?
render custom component on table based on the value of my data object?

Time:09-27

I have a Table component which I want to render custom component based on my data (which is an array of objects) also I need my component (I mean Table component) to have two props, one is the data object and another one is an array of objects which each object has two properties: a title and a function that render different component based on the data key. for example if the key in data object is fullName, I need to render a paragraph tag or if key is avatar, I need to return an image tag and so on.. let me show in code:

const Table = () => {
    const data= [
        {
            id: 1,
            avatar: 'blah blah blah',
            fullName: 'Arlan Pond',
            email: '[email protected]',
            country: 'Brazil',
            registerDate: '1/11/2021',
            status: 'active',
        },
    ];

    const cols = [
        {
            title: 'ID',
            componentToRender(rowsArr) { //this is how I defined my method.
                rowsArr.map((el, index) => {
                    return <td>{el.id}</td>;
                });
            },
        },
        {
            title: 'Avatar',
            componentToRender(rowsArr) { //this is how I defined my method.
                rowsArr.map((el, index) => {
                    return <td><span>{el.avatar}</span></td>;
                });
            },
        },
    ];

    return (
        <div className='table-responsive' style={{width: '95%'}}>
            <table className='table table-borderless'>
                <thead>
                    <tr>
                        //here I need to show my headers...
                        {cols.map((el, index) => { 
                            return <th key={index}>{el.title}</th>;
                        })}
                    </tr>
                </thead>
                <tbody>
                    //here I need to fill my table with components.
                    <tr className='table-row'>
                        {cols.map((el, index) => { 
                            return el.componentToRender(data);
                        })}
                    </tr>
                </tbody>
            </table>
        </div>
    );
};

and the problem is table show only headers but data cells are empty. how can I achieve this?

CodePudding user response:

This is one of the objects that you have defined.

{
            title: 'ID',
            componentToRender(rowsArr) { //this is how I defined my method.
                rowsArr.map((el, index) => {
                    return <td>{el.id}</td>;
                });
            },
        }

if you look closely , you will see that you are not returning anything from the function. The return keyword that you have used, goes back to the map method. So to fix the problem, you will need to change the code like this:

{
            title: 'ID',
            componentToRender(rowsArr) { //this is how I defined my method.
                return rowsArr.map((el, index) => {
                    return <td>{el.id}</td>;
                });
            },
        }

CodePudding user response:

I refactored the component rendering. Instead of looping trough data in every component render, I created a data.map inside <tbody>, which creates a <tr> for every data entry (every object inside data array) and then renders the needed component based on the title.

Beware! title in cols should have the same naming case as the one in data. (for example both should be Avatar or avatar)

import "./styles.css";

const Table = () => {

  const data= [
    {
        ID: 1,
        Avatar: 'blah blah blah', // Capitalized like the Avatar in cols
        fullName: 'Arlan Pond',
        email: '[email protected]',
        country: 'Brazil',
        registerDate: '1/11/2021',
        status: 'active',
    },
    {
      ID: 2,
      Avatar: 'blah blah blah2',
      fullName: 'Arlan Pond',
      email: '[email protected]',
      country: 'Brazil',
      registerDate: '1/11/2021',
      status: 'active',
  },
  ];
  
  const cols = [
    // refactored the components
    {
        title: 'ID',
        component(content) { return <td>{content}</td> }
    },
    {
        title: 'Avatar',
        component(content) { return <td><span>{content}</span></td> }
    },
  ];
  
  return (
      <div className='table-responsive' style={{width: '95%'}}>
          <table className='table table-borderless'>
              <thead>
                  <tr>
                      {cols.map((el, index) => { 
                          return <th key={index}>{el.title}</th>;
                      })}
                  </tr>
              </thead>
              <tbody> 
                {/* completely changed here */}
                {data.map((entry, entryindex) => {
                  return <tr className='table-row'>
                    {cols.map((el, index) => { 
                      return el.component(data[entryindex][el.title])
                    })}
                  </tr>
                })}
              </tbody>
          </table>
      </div>
  );
};

export default function App() {
  return (
    <div className="App">
      <Table />
    </div>
  );
}

See it live in Codesandbox

  • Related