Skip to content

Commit

Permalink
Fixed #2454 and #2455 - Add selectionPageOnly, showSelectAll, selectA…
Browse files Browse the repository at this point in the history
…ll and onSelectAll properties to DataTable
  • Loading branch information
mertsincan committed Nov 20, 2021
1 parent 17cd1b4 commit 99b5b6a
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 37 deletions.
12 changes: 11 additions & 1 deletion src/components/datatable/DataTable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,15 @@ interface DataTableFilterParams {
interface DataTableSelectionChangeParams {
originalEvent: React.SyntheticEvent;
value: any;
type?: string;
[key: string]: any;
}

interface DataTableSelectAllChangeParams {
originalEvent: React.SyntheticEvent;
checked: boolean;
}

interface DataTableRowEventParams {
originalEvent: React.SyntheticEvent;
data: any;
Expand Down Expand Up @@ -256,6 +262,9 @@ export interface DataTableProps {
dataKey?: string;
metaKeySelection?: boolean;
selectOnEdit?: boolean;
selectionPageOnly?: boolean;
showSelectAll?: boolean;
selectAll?: boolean;
headerColumnGroup?: React.ReactNode;
footerColumnGroup?: React.ReactNode;
expandedRows?: any[] | DataTableExpandedRows;
Expand Down Expand Up @@ -296,7 +305,8 @@ export interface DataTableProps {
collapsedRowIcon?: string;
globalFilterFields?: string[];
rowGroupHeaderTemplate?: DataTableRowGroupHeaderTemplateType;
rowGroupFooterTemplate?: DataTableRowGroupFooterTemplateType
rowGroupFooterTemplate?: DataTableRowGroupFooterTemplateType;
onSelectAllChange?(e: DataTableSelectAllChangeParams): void;
onRowEditComplete?(e: DataTableRowEditCompleteParams): void;
showSelectionElement?(data: any, options: DataTableShowSelectionElementOptions): boolean | undefined | null;
showRowReorderElement?(data: any, options: DataTableShowRowReorderElementOptions): boolean | undefined | null;
Expand Down
65 changes: 44 additions & 21 deletions src/components/datatable/DataTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ export class DataTable extends Component {
dataKey: null,
metaKeySelection: true,
selectOnEdit: true,
selectionPageOnly: false,
showSelectAll: true,
selectAll: false,
onSelectAllChange: null,
headerColumnGroup: null,
footerColumnGroup: null,
rowExpansionTemplate: null,
Expand Down Expand Up @@ -175,6 +179,10 @@ export class DataTable extends Component {
dataKey: PropTypes.string,
metaKeySelection: PropTypes.bool,
selectOnEdit: PropTypes.bool,
selectionPageOnly: PropTypes.bool,
showSelectAll: PropTypes.bool,
selectAll: PropTypes.bool,
onSelectAllChange: PropTypes.func,
headerColumnGroup: PropTypes.any,
footerColumnGroup: PropTypes.any,
rowExpansionTemplate: PropTypes.func,
Expand Down Expand Up @@ -320,6 +328,10 @@ export class DataTable extends Component {
return ObjectUtils.isEmpty(this.props.virtualScrollerOptions) || !this.props.scrollable;
}

isEquals(data1, data2) {
return this.props.compareSelectionBy === 'equals' ? (data1 === data2) : ObjectUtils.equals(data1, data2, this.props.dataKey);
}

hasFilter() {
return ObjectUtils.isNotEmpty(this.getFilters()) || this.props.globalFilter;
}
Expand Down Expand Up @@ -633,10 +645,16 @@ export class DataTable extends Component {
}

allRowsSelected(processedData) {
const val = this.props.frozenValue ? [...this.props.frozenValue, ...processedData] : processedData;
const selectableVal = this.props.showSelectionElement ? val.filter((data, index) => this.props.showSelectionElement(data, { rowIndex: index, props: this.props })) : val;
const length = this.props.lazy ? this.props.totalRecords : (selectableVal ? selectableVal.length : 0);
return (selectableVal && length > 0 && this.props.selection && this.props.selection.length > 0 && this.props.selection.length === length);
if (this.props.onSelectAllChange) {
return this.props.selectAll;
}
else {
const data = this.props.selectionPageOnly ? this.dataToRender(processedData) : processedData;
const val = this.props.frozenValue ? [...this.props.frozenValue, ...data] : data;
const selectableVal = this.props.showSelectionElement ? val.filter((data, index) => this.props.showSelectionElement(data, { rowIndex: index, props: this.props })) : val;

return selectableVal && this.props.selection && selectableVal.every(sv => this.props.selection.some(s => this.isEquals(s, sv)));
}
}

getSelectionModeInColumn(columns) {
Expand Down Expand Up @@ -814,26 +832,31 @@ export class DataTable extends Component {
}

onColumnHeaderCheckboxChange(e, processedData) {
const { originalEvent, checked } = e;
let selection;

if (!checked) {
selection = this.props.frozenValue ? [...this.props.frozenValue, ...processedData] : processedData;
selection = this.props.showSelectionElement ? selection.filter((data, index) => this.props.showSelectionElement(data, { rowIndex: index, props: this.props })) : selection;

this.props.onAllRowsSelect && this.props.onAllRowsSelect({ originalEvent, data: selection, type: 'all' });
if (this.props.onSelectAllChange) {
this.props.onSelectAllChange(e);
}
else {
selection = [];
const { originalEvent, checked } = e;
const data = this.props.selectionPageOnly ? this.dataToRender(processedData) : processedData;
let selection = this.props.selectionPageOnly && this.props.selection ? this.props.selection.filter(s => !data.some(d => this.isEquals(s, d))) : [];

this.props.onAllRowsUnselect && this.props.onAllRowsUnselect({ originalEvent, data: selection, type: 'all' });
}
if (!checked) {
selection = this.props.frozenValue ? [...selection, ...this.props.frozenValue, ...data] : [...selection, ...data];
selection = this.props.showSelectionElement ? selection.filter((data, index) => this.props.showSelectionElement(data, { rowIndex: index, props: this.props })) : selection;

if (this.props.onSelectionChange) {
this.props.onSelectionChange({
originalEvent,
value: selection
});
this.props.onAllRowsSelect && this.props.onAllRowsSelect({ originalEvent, data: selection, type: 'all' });
}
else {
this.props.onAllRowsUnselect && this.props.onAllRowsUnselect({ originalEvent, data: selection, type: 'all' });
}

if (this.props.onSelectionChange) {
this.props.onSelectionChange({
originalEvent,
value: selection,
type: 'all'
});
}
}
}

Expand Down Expand Up @@ -1582,7 +1605,7 @@ export class DataTable extends Component {
onColumnResizeStart={this.onColumnResizeStart} onColumnResizerClick={this.props.onColumnResizerClick} onColumnResizerDoubleClick={this.props.onColumnResizerDoubleClick}
sortMode={this.props.sortMode} sortField={sortField} sortOrder={sortOrder} multiSortMeta={multiSortMeta} groupRowsBy={this.props.groupRowsBy} groupRowSortField={groupRowSortField} onSortChange={this.onSortChange}
filterDisplay={this.props.filterDisplay} filters={filters} filtersStore={filtersStore} onFilterChange={this.onFilterChange} onFilterApply={this.onFilterApply}
allRowsSelected={this.allRowsSelected} onColumnCheckboxChange={this.onColumnHeaderCheckboxChange}
showSelectAll={this.props.showSelectAll} allRowsSelected={this.allRowsSelected} onColumnCheckboxChange={this.onColumnHeaderCheckboxChange}
onColumnMouseDown={this.onColumnHeaderMouseDown} onColumnDragStart={this.onColumnHeaderDragStart} onColumnDragOver={this.onColumnHeaderDragOver} onColumnDragLeave={this.onColumnHeaderDragLeave} onColumnDrop={this.onColumnHeaderDrop}
rowGroupMode={this.props.rowGroupMode} reorderableColumns={this.props.reorderableColumns} />
)
Expand Down
2 changes: 1 addition & 1 deletion src/components/datatable/HeaderCell.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ export class HeaderCell extends Component {
}

renderCheckbox() {
if (this.getColumnProp('selectionMode') === 'multiple' && this.props.filterDisplay !== 'row') {
if (this.props.showSelectAll && this.getColumnProp('selectionMode') === 'multiple' && this.props.filterDisplay !== 'row') {
const allRowsSelected = this.props.allRowsSelected(this.props.value);

return (
Expand Down
21 changes: 12 additions & 9 deletions src/components/datatable/TableBody.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class TableBody extends Component {
if (this.allowCellSelection())
return (data1.rowIndex === data2.rowIndex || data1.rowData === data2.rowData) && (data1.field === data2.field || data1.cellIndex === data2.cellIndex)
else
return this.compareSelectionBy === 'equals' ? (data1 === data2) : ObjectUtils.equals(data1, data2, this.props.dataKey);
return this.props.compareSelectionBy === 'equals' ? (data1 === data2) : ObjectUtils.equals(data1, data2, this.props.dataKey);
}

isSubheaderGrouping() {
Expand Down Expand Up @@ -269,7 +269,8 @@ export class TableBody extends Component {
if (this.props.onSelectionChange && selection !== this.props.selection) {
this.props.onSelectionChange({
originalEvent,
value: selection
value: selection,
type
});
}
}
Expand Down Expand Up @@ -300,12 +301,13 @@ export class TableBody extends Component {
if (this.props.onSelectionChange && selection !== this.props.selection) {
this.props.onSelectionChange({
originalEvent,
value: selection
value: selection,
type
});
}
}

onRangeSelection(event) {
onRangeSelection(event, type) {
DomHandler.clearSelection();
this.rangeRowIndex = this.allowCellSelection() ? event.rowIndex : event.index;
let selectionInRange = this.selectRange(event);
Expand All @@ -314,7 +316,8 @@ export class TableBody extends Component {
if (this.props.onSelectionChange && selection !== this.props.selection) {
this.props.onSelectionChange({
originalEvent: event.originalEvent,
value: selection
value: selection,
type
});
}

Expand Down Expand Up @@ -461,7 +464,7 @@ export class TableBody extends Component {

if (this.allowRowSelection()) {
if (this.allowRangeSelection(event)) {
this.onRangeSelection(event);
this.onRangeSelection(event, 'row');
}
else {
const toggleable = this.isRadioSelectionModeInColumn() || this.isCheckboxSelectionModeInColumn() || this.allowMetaKeySelection(event);
Expand Down Expand Up @@ -542,7 +545,7 @@ export class TableBody extends Component {
onRowMouseUp(event) {
const isSameRow = event.index === this.anchorRowIndex;
if (this.allowRowDrag(event) && !isSameRow) {
this.onRangeSelection(event);
this.onRangeSelection(event, 'row');
}
}

Expand Down Expand Up @@ -722,7 +725,7 @@ export class TableBody extends Component {

if (this.allowCellSelection()) {
if (this.allowRangeSelection(event)) {
this.onRangeSelection(event);
this.onRangeSelection(event, 'cell');
}
else {
let toggleable = this.allowMetaKeySelection(event);
Expand Down Expand Up @@ -757,7 +760,7 @@ export class TableBody extends Component {
onCellMouseUp(event) {
const isSameCell = event.rowIndex === this.anchorRowIndex && event.cellIndex === this.anchorCellIndex;
if (this.allowCellDrag(event) && !isSameCell) {
this.onRangeSelection(event);
this.onRangeSelection(event, 'cell');
}
}

Expand Down
31 changes: 27 additions & 4 deletions src/components/datatable/TableHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,33 @@ export class TableHeader extends Component {
filterDisplay={this.props.filterDisplay} filters={this.props.filters} filtersStore={this.props.filtersStore} onFilterChange={this.props.onFilterChange} onFilterApply={this.props.onFilterApply}
onColumnMouseDown={this.props.onColumnMouseDown} onColumnDragStart={this.props.onColumnDragStart} onColumnDragOver={this.props.onColumnDragOver} onColumnDragLeave={this.props.onColumnDragLeave} onColumnDrop={this.props.onColumnDrop}
onColumnResizeStart={this.props.onColumnResizeStart} onColumnResizerClick={this.props.onColumnResizerClick} onColumnResizerDoubleClick={this.props.onColumnResizerDoubleClick}
allRowsSelected={this.props.allRowsSelected} onColumnCheckboxChange={this.onCheckboxChange} reorderableColumns={this.props.reorderableColumns} onSortChange={this.props.onSortChange} />
showSelectAll={this.props.showSelectAll} allRowsSelected={this.props.allRowsSelected} onColumnCheckboxChange={this.onCheckboxChange} reorderableColumns={this.props.reorderableColumns} onSortChange={this.props.onSortChange} />
);
});
}

renderCheckbox(selectionMode) {
if (this.props.showSelectAll && selectionMode === 'multiple') {
const allRowsSelected = this.props.allRowsSelected(this.props.value);

return (
<HeaderCheckbox checked={allRowsSelected} onChange={this.onCheckboxChange} disabled={this.props.empty} />
)
}

return null;
}

renderFilter(column, filter) {
if (filter) {
return (
<ColumnFilter display="row" column={column} filters={this.props.filters} filtersStore={this.props.filtersStore} onFilterChange={this.props.onFilterChange} onFilterApply={this.props.onFilterApply} />
)
}

return null;
}

renderFilterCells() {
return React.Children.map(this.props.columns, (col, i) => {
const isVisible = !col.props.hidden;
Expand All @@ -96,12 +118,13 @@ export class TableHeader extends Component {
const colStyle = { ...(filterHeaderStyle || {}), ...(style || {}) };
const colClassName = classNames('p-filter-column', filterHeaderClassName, className, { 'p-frozen-column': frozen });
const colKey = columnKey || field || i;
const allRowsSelected = selectionMode === 'multiple' && this.props.allRowsSelected(this.props.value);
const checkbox = this.renderCheckbox(selectionMode);
const filterRow = this.renderFilter(col, filter);

return (
<th key={colKey} style={colStyle} className={colClassName}>
{selectionMode === 'multiple' && <HeaderCheckbox checked={allRowsSelected} onChange={this.onCheckboxChange} disabled={this.props.empty} />}
{filter && <ColumnFilter display="row" column={col} filters={this.props.filters} filtersStore={this.props.filtersStore} onFilterChange={this.props.onFilterChange} onFilterApply={this.props.onFilterApply} />}
{checkbox}
{filterRow}
</th>
)
}
Expand Down
27 changes: 26 additions & 1 deletion src/showcase/datatable/DataTableDoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3129,6 +3129,24 @@ export const DataTableStateDemo = () => {
<td>true</td>
<td>Determines whether the cell editor will be opened when clicking to select any row on Selection and Cell Edit modes.</td>
</tr>
<tr>
<td>selectionPageOnly</td>
<td>boolean</td>
<td>false</td>
<td>When enabled with paginator and checkbox selection mode, the select all checkbox in the header will select all rows on the current page.</td>
</tr>
<tr>
<td>showSelectAll</td>
<td>boolean</td>
<td>true</td>
<td>Whether to show the select all checkbox in the header.</td>
</tr>
<tr>
<td>selectAll</td>
<td>boolean</td>
<td>false</td>
<td>Whether all data is selected.</td>
</tr>
<tr>
<td>headerColumnGroup</td>
<td>ColumnGroup</td>
Expand Down Expand Up @@ -3441,7 +3459,8 @@ export const DataTableStateDemo = () => {
<tr>
<td>onSelectionChange</td>
<td>event.originalEvent: Browser event <br/>
event.value: Selection object
event.value: Selection object <br />
event.type: Type of the selection, valid values are "all", "row", "cell", "radio" and "checkbox".
</td>
<td>Callback to invoke when selection changes.</td>
</tr>
Expand Down Expand Up @@ -3496,6 +3515,12 @@ export const DataTableStateDemo = () => {
<td>event.filters: Collection of active filters.</td>
<td>Callback to invoke on filtering.</td>
</tr>
<tr>
<td>onSelectAll</td>
<td>event.originalEvent: Browser event<br />
event.checked: Whether all data is selected.</td>
<td>Callback to invoke when all data is selected.</td>
</tr>
<tr>
<td>onAllRowsSelect</td>
<td>event.originalEvent: Browser event. <br />
Expand Down

0 comments on commit 99b5b6a

Please sign in to comment.