Search code examples
datagridtabsshowreact-admin

React-Admin - How to create a Datagrid without a List in React-Admin


How to create a Datagrid without a List in React-Admin?

In React-admin to be able to use Datagrid to show the values you need to nest it inside a List like that:

<List {...props}>
 <Datagrid> 
  <Textfield source"name" />
 <Datagrid />
<List/>

But I need to use the dDatagrid outside of the List. The values of the Datagrid must to be shown in a screen of the type inside a Tab.


Solution

  • Here how I solved that problem using React-Admin 2.9

    First I used The import { Query } from 'react-admin'; to fetch the data from the endpoint data/product and after that It converted the IDs to the key of it's own data.

    To the commponent CustomDatagrid was passed two arrays the will be used to show the values. The first is a array of IDs and the second array is the array that contains the data and uses IDs as its key to be able to access the values.

    ProductShow.js

    import React, { useState } from 'react';
    import PropTypes from 'prop-types';
    import { connect } from 'react-redux';
    import {
      TextField,
      Query,
      showNotification,
      // ReferenceField,
      DateField,
    } from 'react-admin';
    import CustomDatagrid from './CustomDatagrid';
    
    const convertKeyToIndice = (datas) => {
      const { data } = datas;
      let ids = [];
      const dataKey = [];
    
      if (data) {
        ids = data.map((elemento) => {
          dataKey[elemento.id] = elemento;
          return elemento.id;
        });
        return ({ ids, dataKey });
      }
      return ({});
    };
    
    const ProductShow = (props) => {
      const { record } = props;
      const { productId, dateValue } = record;
    
      const [newPage, setNewPage] = useState(0);
      const [rowsPerPage, setRowsPerPage] = useState(50);
    
      const filter = {
        pagination: { page: newPage + 1, perPage: rowsPerPage },
        sort: { field: 'id', order: 'ASC' },
        filter: { productId, dateValue: dateValue },
      };
    
      return (
        <Query type="GET_LIST" resource="data/product" payload={filter}>
          {(datas) => {
            if (datas.loading && !datas.error) { return <div>Wait...</div>; }
            if (datas.error) {
              props.showNotification('Not Found');
              return <div />;
            }
    
            const dataGridValues = {
              ...convertKeyToIndice(datas),
              total: datas.total,
              rowsPerPage,
              setRowsPerPage,
              newPage,
              setNewPage,
            };
    
            return (
              <>
                <CustomDatagrid dataGridValues={dataGridValues}>
                  {/* <ReferenceField
                    sortBy="product.id"
                    source="productId"
                    reference="product"
                    linkType={false}
                    allowEmpty
                    {...props}
                    label="product"
                  >
                    <TextField source="name" />
                  </ReferenceField> */}
                  <DateField label="Date" source="valueDate" showTime />
                  <TextField label="Value1" source="value1" />
                  <TextField label="Value2"  source="value2" />
                  <TextField label="Value3"  source="value3" />
                  <TextField label="Value4" source="value4" />
                  <TextField label="Value5" source="value5" />
    
                </CustomDatagrid>
              </>
    
            );
          }}
        </Query>
      );
    };
    
    ProductShow.propTypes = {
      productId: PropTypes.string.isRequired,
      dateValue: PropTypes.string.isRequired,
      showNotification: PropTypes.func.isRequired,
      record: PropTypes.oneOfType([PropTypes.object]).isRequired,
    };
    
    export default connect(null, { showNotification })(ProductShow);
    
    

    In the TableHead it shows the label of each column following the order that you wrap the Components in the CustomDatagrid inside the parent ProductShow component.

    To Show The Components Like the List of React-Admin would show, is used the

                        {React.cloneElement(child,
                          { record: dataKey[id] },
                          (child.props.children ? child.props.children : null))}
    

    CustomDatagrid.js

    import React from 'react';
    import {
      Table,
      TableRow,
      TableHead,
      TableCell,
      TableBody,
      TablePagination,
    } from '@material-ui/core';
    import PropTypes from 'prop-types';
    
    const CustomDatagrid = (propsDataGrid) => {
      const { children, dataGridValues } = propsDataGrid;
      const {
        dataKey,
        ids,
        total,
        rowsPerPage,
        setRowsPerPage,
        setNewPage,
        newPage,
      } = dataGridValues;
    
      const handleChangePage = (event, page) => {
        setNewPage(page);
      };
    
      const handleChangeRowsPerPage = (event) => {
        const vlrDecimal = parseInt(event.target.value, 10);
        setRowsPerPage(vlrDecimal);
    
        setNewPage(0);
      };
    
      return (
        <>
          <Table style={{ width: '100%' }}>
            <TableHead>
              <TableRow>
                {children && children.map(({ props }) => (
                  <TableCell>
                    {props && props.label ? props.label : props.source}
                  </TableCell>
                ))
              }
              </TableRow>
            </TableHead>
            <TableBody>
              {ids && ids.map(id => (
                <TableRow>
                  {React.Children.map(children,
                    child => (
                      <TableCell>
    
                        {React.cloneElement(child,
                          { record: dataKey[id] },
                          (child.props.children ? child.props.children : null))}
    
                      </TableCell>
                    ))}
                </TableRow>
              ))
              }
            </TableBody>
          </Table>
          <TablePagination
            rowsPerPageOptions={[50, 100, 250]}
            component="div"
            count={total}
            rowsPerPage={rowsPerPage}
            page={newPage}
            onChangePage={handleChangePage}
            onChangeRowsPerPage={handleChangeRowsPerPage}
            labelRowsPerPage="Results per Page:"
          />
        </>
      );
    };
    
    
    CustomDatagrid.propTypes = {
      source: PropTypes.string.isRequired,
      label: PropTypes.string.isRequired,
    };
    
    
    export default CustomDatagrid;