Как построить столбцы таблицы, используя несколько полей, возвращаемых API? - PullRequest
1 голос
/ 06 августа 2020

Мне нужно предварительно обработать данные, поступающие из API. Необработанные данные имеют следующий формат:

enter image description here

I want to dynamically build a Table, in which the columns should be created using fields task_name and saved_answers. Please notice that saved_answers may contain different sub-fields depending on the task_name. In other words, saved_answers does not always contain value21, value22, value23 and value24.

Below I show an example of a table.

============================================================================================================
| user_id  |  task11-value21  |   task11-value22  |   task11-value23  |  task11-value24  | task13-valueMu...
============================================================================================================
| 111      |  1               |   1               |   1               |  1               | 5
... 

So far I only can retrieve the data from API and show specific columns in the table. I would highly appreciate any help. Thanks.

import React, { useEffect } from 'react'
import { makeStyles } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';
import axios from 'axios'
import config from '../../config/config.json';

const useStyles = makeStyles((theme) => ({
    root: {
        width: '100%',
    },
    heading: {
        fontSize: theme.typography.pxToRem(18),
        fontWeight: theme.typography.fontWeightBold,
    },
    content: {
        fontSize: theme.typography.pxToRem(14),
        fontWeight: theme.typography.fontWeightRegular,
        textAlign: "left",
        marginTop: theme.spacing.unit*3,
        marginLeft: theme.spacing.unit*3,
        marginRight: theme.spacing.unit*3
    },
    table: {
        minWidth: 650,
    },
    tableheader: {
        fontWeight: theme.typography.fontWeightBold,
        color: "#ffffff",
        background: "#3f51b5"
    }
}));


export function Main() {

    const [groupKey,setGroupKey] = React.useState([]);

    const classes = useStyles();

    const options = {
        'headers': {
            'Authorization': `Bearer ${localStorage.getItem('accessToken')}`
        }
    }

    useEffect(() => {
        axios.get(config.api.url + '/api/test', options)
            .then( (groups) => {
                setGroupKey(groups);
                console.log(groups);
            })
            .catch( (error) => {
                console.log(error);
            })
    }, []);

    return (
        

            
                
                    
                        
                            
                                
                                    Group
                                    Task name
                                
                            
                            
                                {groupKey.map( (row, index) => (
                                     {row.user_id}  {row.task_name}  ))}      )} 

ОБНОВЛЕНИЕ:

import '../../App.css';
import React, { useEffect } from 'react'
import PropTypes from 'prop-types';
import { makeStyles, useTheme } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import TablePagination from '@material-ui/core/TablePagination';
import TableFooter from '@material-ui/core/TableFooter';
import IconButton from '@material-ui/core/IconButton';
import FirstPageIcon from '@material-ui/icons/FirstPage';
import KeyboardArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
import KeyboardArrowRight from '@material-ui/icons/KeyboardArrowRight';
import LastPageIcon from '@material-ui/icons/LastPage';
import Paper from '@material-ui/core/Paper';
import axios from 'axios'
import config from '../../config/config.json';

const useStyles = makeStyles((theme) => ({
    root: {
        width: '100%',
    },
    heading: {
        fontSize: theme.typography.pxToRem(18),
        fontWeight: theme.typography.fontWeightBold,
    },
    content: {
        fontSize: theme.typography.pxToRem(14),
        fontWeight: theme.typography.fontWeightRegular,
        textAlign: "left",
        marginTop: theme.spacing.unit*3,
        marginLeft: theme.spacing.unit*3,
        marginRight: theme.spacing.unit*3
    },
    table: {
        minWidth: 650,
    },
    tableheader: {
        fontWeight: theme.typography.fontWeightBold,
        color: "#ffffff",
        background: "#3f51b5"
    },
    tableCell: {
        color: "#000000",
        background: "#ffffff"
    },
    button: {
        fontSize: "12px",
        minWidth: 100
    },
}));


function TablePaginationActions(props) {
    const classes = useStyles();
    const theme = useTheme();
    const { count, page, rowsPerPage, onChangePage } = props;
  
    const handleFirstPageButtonClick = (event) => {
      onChangePage(event, 0);
    };
  
    const handleBackButtonClick = (event) => {
      onChangePage(event, page - 1);
    };
  
    const handleNextButtonClick = (event) => {
      onChangePage(event, page + 1);
    };
  
    const handleLastPageButtonClick = (event) => {
      onChangePage(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1));
    };
  
    return (
      <div className={classes.root}>
        <IconButton
          onClick={handleFirstPageButtonClick}
          disabled={page === 0}
          aria-label="first page"
        >
          {theme.direction === 'rtl' ? <LastPageIcon /> : <FirstPageIcon />}
        </IconButton>
        <IconButton onClick={handleBackButtonClick} disabled={page === 0} aria-label="previous page">
          {theme.direction === 'rtl' ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
        </IconButton>
        <IconButton
          onClick={handleNextButtonClick}
          disabled={page >= Math.ceil(count / rowsPerPage) - 1}
          aria-label="next page"
        >
          {theme.direction === 'rtl' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
        </IconButton>
        <IconButton
          onClick={handleLastPageButtonClick}
          disabled={page >= Math.ceil(count / rowsPerPage) - 1}
          aria-label="last page"
        >
          {theme.direction === 'rtl' ? <FirstPageIcon /> : <LastPageIcon />}
        </IconButton>
      </div>
    );
  }


  function getGridHeader(config) {
    const gridHeader = ["user_id"];
    console.log(config);
    const savedAnswers = Object.keys(JSON.parse(config.saved_answers));
    savedAnswers.map(savedAnswer => {
      gridHeader.push(`${config.task_name}-${savedAnswer}`)
    });
    return gridHeader;
  }

  
  function getGridData(config) {
    const gridData = [config.user_id];
    const savedAnswers = JSON.parse(config.saved_answers);
    Object.keys(savedAnswers).map( savedAnswer => {
      gridData.push(savedAnswers[savedAnswer]);
    });
    return gridData;
  }

  
  TablePaginationActions.propTypes = {
    count: PropTypes.number.isRequired,
    onChangePage: PropTypes.func.isRequired,
    page: PropTypes.number.isRequired,
    rowsPerPage: PropTypes.number.isRequired,
  };


export function Main() {

    const [groupKey,setGroupKey] = React.useState([]);
    const [page, setPage] = React.useState(0);
    const [rowsPerPage, setRowsPerPage] = React.useState(5);
    const emptyRows = rowsPerPage - Math.min(rowsPerPage, groupKey.length - page * rowsPerPage);

    const gridHeader = getGridHeader(groupKey);
    const gridData = getGridData(groupKey);

    const handleChangePage = (event, newPage) => {
        setPage(newPage);
    };

    const handleChangeRowsPerPage = (event) => {
        setRowsPerPage(parseInt(event.target.value, 10));
        setPage(0);
    };

    const classes = useStyles();

    const options = {
        'headers': {
            'Authorization': `Bearer ${localStorage.getItem('accessToken')}`
        }
    }

    useEffect(() => {
        axios.get(config.api.url + '/api/test', options)
            .then( (groups) => {
                setGroupKey(groups.data.subtask);
            })
            .catch( (error) => {
                console.log(error);
            })
    }, []);

    return (
        <div className={classes.root}>

            <Grid container spacing={3}>
                <Grid item xs={12} className={classes.content}>

                <TableContainer component={Paper}>
                    <Table className={classes.table}>
                        <TableHead>
                            <TableRow className={classes.tableheader}>
                                {gridHeader.map( (headerTitle, index) => (
                                <TableCell key={index}>{headerTitle}</TableCell>
                                ))}
                            </TableRow>
                        </TableHead>
                        <TableBody>
                        {(rowsPerPage > 0
                            ? gridData.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
                            : gridData
                        ).map((cellValue, index) => (
                            <TableRow key={index} selected="false">
                                <TableCell className={classes.tableCell}component="th" scope="row">{cellValue}</TableCell>
                            </TableRow>
                        ))}

                        {emptyRows > 0 && (
                            <TableRow style={{ height: 53 * emptyRows }}>
                            <TableCell colSpan={6} />
                            </TableRow>
                        )}
                        </TableBody>
                        <TableFooter>
                            <TableRow>
                                <TablePagination
                                    rowsPerPageOptions={[5, 10, 25, { label: 'All', value: -1 }]}
                                    colSpan={3}
                                    count={groupKey.length}
                                    rowsPerPage={rowsPerPage}
                                    page={page}
                                    SelectProps={{
                                        inputProps: { 'aria-label': 'groups per page' },
                                        native: true,
                                    }}
                                    onChangePage={handleChangePage}
                                    onChangeRowsPerPage={handleChangeRowsPerPage}
                                    ActionsComponent={TablePaginationActions}
                                />
                            </TableRow>
                        </TableFooter>
                    </Table>
                    </TableContainer>

                </Grid>    
            </Grid>
        </div>
    )
}

1 Ответ

1 голос
/ 06 августа 2020

Итак, алгоритм следующий:

  1. генерировать массив заголовков из необработанных данных
  2. генерировать массив массивов для данных тела таблицы на основе user_id

Надеюсь, у вас это получится.

Используя эти два массива, вы можете перебирать и создавать свою таблицу данных, например:

enter image description here

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';

const useStyles = makeStyles({
  table: {
    minWidth: 650,
  },
});

function generateRandomSavedAnswer(rowIndex, maxNumberOfSavedAnswers) {
  //const numberOfSavedAnswers = Math.floor(Math.random()*maxNumberOfSavedAnswers);
  const savedAnswers = {};
  for(let i=0; i {
    gridHeader.push(`${config.task_name}-${savedAnswer}`)
  });
  return gridHeader;
}

function getGridData(config) {
  const gridData = [config.user_id];
  const savedAnswers = JSON.parse(config.saved_answers);
  Object.keys(savedAnswers).map( savedAnswer => {
    gridData.push(savedAnswers[savedAnswer]);
  });
  return gridData;
}

export default function SimpleTable() {
  const classes = useStyles();
  const gridRawData = generateGridRawData();
  const gridHeader = getGridHeader(gridRawData[0]);
  const gridData = getGridData(gridRawData[0]);

  return (
    
        {gridHeader.map ((headerTitle, index) => ( {headerTitle} ))}    {gridData.map ((cellValue, index) => ( {cellValue} ))}    ); } 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...