• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

gregnb / mui-datatables / #1880

01 Aug 2019 07:29AM UTC coverage: 74.963% (+3.7%) from 71.311%
#1880

push

gabrielliwerant
2.7.0

444 of 611 branches covered (72.67%)

Branch coverage included in aggregate %.

568 of 739 relevant lines covered (76.86%)

85.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

85.37
/src/components/TableBody.js
1
import React from 'react';
2
import PropTypes from 'prop-types';
3
import Typography from '@material-ui/core/Typography';
4
import MuiTableBody from '@material-ui/core/TableBody';
5
import TableBodyCell from './TableBodyCell';
6
import TableBodyRow from './TableBodyRow';
7
import TableSelectCell from './TableSelectCell';
8
import { withStyles } from '@material-ui/core/styles';
9

10
const defaultBodyStyles = {
1✔
11
  root: {},
12
  emptyTitle: {
13
    textAlign: 'center',
14
  },
15
};
16

17
class TableBody extends React.Component {
18
  static propTypes = {
19
    /** Data used to describe table */
20
    data: PropTypes.array.isRequired,
21
    /** Total number of data rows */
22
    count: PropTypes.number.isRequired,
23
    /** Columns used to describe table */
24
    columns: PropTypes.array.isRequired,
25
    /** Options used to describe table */
26
    options: PropTypes.object.isRequired,
27
    /** Data used to filter table against */
28
    filterList: PropTypes.array,
29
    /** Callback to execute when row is clicked */
30
    onRowClick: PropTypes.func,
31
    /** Table rows selected */
32
    selectedRows: PropTypes.object,
33
    /** Callback to trigger table row select */
34
    selectRowUpdate: PropTypes.func,
35
    /** Data used to search table against */
36
    searchText: PropTypes.string,
37
    /** Toggle row expandable */
38
    toggleExpandRow: PropTypes.func,
39
    /** Extend the style applied to components */
40
    classes: PropTypes.object,
41
  };
42

43
  static defaultProps = {
44
    toggleExpandRow: () => {},
45
  };
46

47
  buildRows() {
48
    const { data, page, rowsPerPage, count } = this.props;
32✔
49

50
    if (this.props.options.serverSide) return data.length ? data : null;
32✔
51

52
    let rows = [];
29✔
53
    const totalPages = Math.floor(count / rowsPerPage);
29✔
54
    const fromIndex = page === 0 ? 0 : page * rowsPerPage;
29✔
55
    const toIndex = Math.min(count, (page + 1) * rowsPerPage);
29✔
56

57
    if (page > totalPages && totalPages !== 0) {
29!
58
      console.warn('Current page is out of range.');
×
59
    }
60

61
    for (let rowIndex = fromIndex; rowIndex < count && rowIndex < toIndex; rowIndex++) {
29✔
62
      if (data[rowIndex] !== undefined) rows.push(data[rowIndex]);
117!
63
    }
64

65
    return rows.length ? rows : null;
29✔
66
  }
67

68
  getRowIndex(index) {
69
    const { page, rowsPerPage, options } = this.props;
235✔
70

71
    if (options.serverSide) {
235✔
72
      return index;
8✔
73
    }
74

75
    const startIndex = page === 0 ? 0 : page * rowsPerPage;
227✔
76
    return startIndex + index;
227✔
77
  }
78

79
  isRowSelected(dataIndex) {
80
    const { selectedRows } = this.props;
231✔
81
    return selectedRows.lookup && selectedRows.lookup[dataIndex] ? true : false;
231!
82
  }
83

84
  isRowExpanded(dataIndex) {
85
    const { expandedRows } = this.props;
234✔
86
    return expandedRows.lookup && expandedRows.lookup[dataIndex] ? true : false;
234!
87
  }
88

89
  isRowSelectable(dataIndex) {
90
    const { options } = this.props;
121✔
91
    if (options.isRowSelectable) {
121✔
92
      return options.isRowSelectable(dataIndex);
5✔
93
    }
94
    return true;
116✔
95
  }
96

97
  handleRowSelect = data => {
98
    this.props.selectRowUpdate('cell', data);
4✔
99
  };
100

101
  handleRowClick = (row, data, event) => {
102
    // Don't trigger onRowClick if the event was actually the expandable icon
103
    if (
7!
104
      event.target.id === 'expandable-button' ||
14!
105
      (event.target.nodeName === 'path' && event.target.parentNode.id === 'expandable-button')
106
    ) {
107
      // In a future release, onRowClick will no longer be called here (for consistency).
108
      // For now, issue a deprecated warning.
109
      if (this.props.options.onRowClick) {
×
110
        console.warn(
×
111
          'Deprecated: Clicks on expandable button will not trigger onRowClick in an upcoming release, see: https://github.com/gregnb/mui-datatables/issues/516.',
112
        );
113
        this.props.options.onRowClick(row, data, event);
×
114
      }
115

116
      return;
×
117
    }
118

119
    // Don't trigger onRowClick if the event was actually a row selection via checkbox
120
    if (event.target.id && event.target.id.startsWith('MUIDataTableSelectCell')) return;
7✔
121

122
    // Check if we should toggle row select when row is clicked anywhere
123
    if (
6✔
124
      this.props.options.selectableRowsOnClick &&
14✔
125
      this.props.options.selectableRows !== 'none' &&
126
      this.isRowSelectable(data.dataIndex)
127
    ) {
128
      const selectRow = { index: data.rowIndex, dataIndex: data.dataIndex };
3✔
129
      this.handleRowSelect(selectRow);
3✔
130
    }
131
    // Check if we should trigger row expand when row is clicked anywhere
132
    if (this.props.options.expandableRowsOnClick && this.props.options.expandableRows) {
6✔
133
      const expandRow = { index: data.rowIndex, dataIndex: data.dataIndex };
2✔
134
      this.props.toggleExpandRow(expandRow);
2✔
135
    }
136

137
    // Don't trigger onRowClick if the event was actually a row selection via click
138
    if (this.props.options.selectableRowsOnClick) return;
6✔
139

140
    this.props.options.onRowClick && this.props.options.onRowClick(row, data, event);
2✔
141
  };
142

143
  render() {
144
    const { classes, columns, toggleExpandRow, options } = this.props;
32✔
145
    const tableRows = this.buildRows();
32✔
146
    const visibleColCnt = columns.filter(c => c.display === 'true').length;
145✔
147

148
    return (
32✔
149
      <MuiTableBody>
150
        {tableRows && tableRows.length > 0 ? (
93✔
151
          tableRows.map((data, rowIndex) => {
152
            const { data: row, dataIndex } = data;
121✔
153

154
            if (options.customRowRender) {
121✔
155
              return options.customRowRender(row, dataIndex, rowIndex);
4✔
156
            }
157

158
            return (
117✔
159
              <React.Fragment key={rowIndex}>
160
                <TableBodyRow
161
                  {...(options.setRowProps ? options.setRowProps(row, dataIndex) : {})}
117✔
162
                  options={options}
163
                  rowSelected={options.selectableRows !== 'none' ? this.isRowSelected(dataIndex) : false}
117✔
164
                  onClick={this.handleRowClick.bind(null, row, { rowIndex, dataIndex })}
165
                  data-testid={'MUIDataTableBodyRow-' + dataIndex}
166
                  id={'MUIDataTableBodyRow-' + dataIndex}>
167
                  <TableSelectCell
168
                    onChange={this.handleRowSelect.bind(null, {
169
                      index: this.getRowIndex(rowIndex),
170
                      dataIndex: dataIndex,
171
                    })}
172
                    onExpand={toggleExpandRow.bind(null, {
173
                      index: this.getRowIndex(rowIndex),
174
                      dataIndex: dataIndex,
175
                    })}
176
                    fixedHeader={options.fixedHeader}
177
                    checked={this.isRowSelected(dataIndex)}
178
                    expandableOn={options.expandableRows}
179
                    selectableOn={options.selectableRows}
180
                    isRowExpanded={this.isRowExpanded(dataIndex)}
181
                    isRowSelectable={this.isRowSelectable(dataIndex)}
182
                    id={'MUIDataTableSelectCell-' + dataIndex}
183
                  />
184
                  {row.map(
185
                    (column, columnIndex) =>
186
                      columns[columnIndex].display === 'true' && (
535✔
187
                        <TableBodyCell
188
                          {...(columns[columnIndex].setCellProps
335!
189
                            ? columns[columnIndex].setCellProps(column, dataIndex, columnIndex)
190
                            : {})}
191
                          data-testid={`MuiDataTableBodyCell-${columnIndex}-${rowIndex}`}
192
                          dataIndex={dataIndex}
193
                          rowIndex={rowIndex}
194
                          colIndex={columnIndex}
195
                          columnHeader={columns[columnIndex].label}
196
                          print={columns[columnIndex].print}
197
                          options={options}
198
                          key={columnIndex}>
199
                          {column}
200
                        </TableBodyCell>
201
                      ),
202
                  )}
203
                </TableBodyRow>
204
                {this.isRowExpanded(dataIndex) && options.renderExpandableRow(row, { rowIndex, dataIndex })}
117!
205
              </React.Fragment>
206
            );
207
          })
208
        ) : (
209
          <TableBodyRow options={options}>
210
            <TableBodyCell
211
              colSpan={options.selectableRows !== 'none' || options.expandableRows ? visibleColCnt + 1 : visibleColCnt}
6!
212
              options={options}
213
              colIndex={0}
214
              rowIndex={0}>
215
              <Typography variant="subtitle1" className={classes.emptyTitle}>
216
                {options.textLabels.body.noMatch}
217
              </Typography>
218
            </TableBodyCell>
219
          </TableBodyRow>
220
        )}
221
      </MuiTableBody>
222
    );
223
  }
224
}
225

226
export default withStyles(defaultBodyStyles, { name: 'MUIDataTableBody' })(TableBody);
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc