Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DataViewModel Supports Multiple, Settable SortBy and GroupBy Fields #1715

Merged
merged 12 commits into from
Feb 26, 2020
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
* `GridModel` and `DataViewModel` now support `groupRowHeight`, `groupRowRenderer` and
`groupRowElementRenderer` configs. Grouping is new in general to `DataViewModel`, which now takes
a `groupBy` config.
* `DataViewModel` also now supports additional configs from the underlying `GridModel` that make
* `DataViewModel` allows for settable and multiple groupings and sorters like GridModel.
* `DataViewModel` also now supports additional configs from the underlying `GridModel` that make
sense in a `DataView` context, such as `showHover` and `rowBorders`.
* `TabContainerModel` now accepts a `track` property (default false) for easily tracking tab views
via Hoist's built-in activity tracking.
Expand Down
1 change: 1 addition & 0 deletions cmp/dataview/DataView.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class LocalModel {

this.agOptions = {
headerHeight: 0,
suppressMakeColumnVisibleAfterUnGroup: true,
getRowHeight: (params) => {
// Return (required) itemHeight for data rows.
if (!params.node?.group) return model.itemHeight;
Expand Down
40 changes: 14 additions & 26 deletions cmp/dataview/DataViewModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@
*/

import {GridModel} from '@xh/hoist/cmp/grid';
import {GridSorter} from '@xh/hoist/cmp/grid/impl/GridSorter';
import {HoistModel, managed} from '@xh/hoist/core';
import {bindable} from '@xh/hoist/mobx';
import {throwIf} from '@xh/hoist/utils/js';
import {castArray, isNumber} from 'lodash';
import {isNumber} from 'lodash';
import {apiRemoved} from '../../utils/js';

/**
Expand All @@ -37,13 +36,13 @@ export class DataViewModel {
* @param {Column~elementRendererFn} c.elementRenderer - function returning a React element for
* each data row.
* @param {number} itemHeight - Row height (in px) for each item displayed in the view.
* @param {string} [c.groupBy] - Column ID by which to do full-width row grouping.
* @param {(string|string[]} [c.groupBy] - field(s) by which to do full-width row grouping.
* @param {number} [c.groupRowHeight] - Height (in px) of a group row.
* @param {Grid~groupRowRendererFn} [c.groupRowRenderer] - function returning a string used to
* render group rows.
* @param {Grid~groupRowElementRendererFn} [c.groupRowElementRenderer] - function returning a React
* element used to render group rows.
* @param {(string|string[]|Object|Object[])} [c.sortBy] - colId(s) or sorter config(s) with
* @param {(string|string[]|Object|Object[])} [c.sortBy] - field(s) or sorter config(s) with
* `colId` and `sort` (asc|desc) keys.
* @param {(StoreSelectionModel|Object|String)} [c.selModel] - StoreSelectionModel, or a
* config or string `mode` from which to create.
Expand All @@ -67,7 +66,7 @@ export class DataViewModel {
groupRowHeight,
groupRowRenderer,
groupRowElementRenderer,
sortBy = [],
sortBy,
selModel,
emptyText,
showHover = false,
Expand All @@ -77,37 +76,22 @@ export class DataViewModel {
rowClassFn,
...restArgs
}) {
sortBy = castArray(sortBy);
throwIf(sortBy.length > 1, 'DataViewModel does not support multiple sorters.');
throwIf(!isNumber(itemHeight), 'Must specify DataViewModel.itemHeight as a number to set a fixed pixel height for each item.');
apiRemoved(restArgs.rowCls, 'rowCls', 'Use \'rowClassFn\' instead.');
apiRemoved(restArgs.itemRenderer, 'itemRenderer', 'Use \'elementRenderer\' instead.');

this.itemHeight = itemHeight;
this.groupRowHeight = groupRowHeight;

// We only have a single visible column in our DataView grid and rely on ag-Grid for sorting,
// initially and through updates via transactions. For this reason, we set the field of our
// single column to the desired sort field. (The field setting should not have any other
// meaningful impact on the grid, since we use a custom renderer and mark it as complex to
// ensure each item re-renders on any record change.)
let field = 'id';
if (sortBy.length === 1) {
let sorter = sortBy[0];
if (!(sorter instanceof GridSorter)) sorter = GridSorter.parse(sorter);
field = sorter.colId;
}

const columns = [{
field,
// We create a single visible 'synthetic' column in our DataView grid to hold our renderer
// Also add hidden columns for all other fields to make sure grouping and sorting works!
const columns = store.fields.map(field => ({field, hidden: true}));
columns.push({
colId: 'xhDataViewColumn',
flex: true,
elementRenderer,
rendererIsComplex: true
}];

if (groupBy) {
columns.push({field: groupBy, hidden: true});
}
});

this.gridModel = new GridModel({
store,
Expand Down Expand Up @@ -135,11 +119,15 @@ export class DataViewModel {
get hasSelection() {return this.gridModel.hasSelection}
get selection() {return this.gridModel.selection}
get selectedRecord() {return this.gridModel.selectedRecord}
get groupBy() {return this.gridModel.groupBy}
get sortBy() {return this.gridModel.sortBy}

selectFirst() {return this.gridModel.selectFirst()}
ensureSelectionVisible() {return this.gridModel.ensureSelectionVisible()}
doLoadAsync(loadSpec) {return this.gridModel.doLoadAsync(loadSpec)}
loadData(...args) {return this.gridModel.loadData(...args)}
updateData(...args) {return this.gridModel.updateData(...args)}
clear() {return this.gridModel.clear()}
setGroupBy(colIds) {return this.gridModel.setGroupBy(colIds)}
setSortBy(sorters) {return this.gridModel.setSortBy(sorters)}
}