Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions docs/data_collection/api/datacollection_add_method.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ component.data.add([

@descr:

When data is [grouped](data_collection/api/datacollection_group_method.md), DataCollection recalculates the [counters and aggregated values](data_collection/api/datacollection_group_method.md#group-counters-and-aggregates) of the groups over the resulting data.

**Related article**: [Controls and operations](window/customization.md#controls-and-operations)

**Related sample**: [Data. Add](https://snippet.dhtmlx.com/ktd8ks0m)

@changelog: The possibility to pass an array of items is added in v6.1.

[comment]: # (@related:window/customization.md#controls-and-operations)
8 changes: 7 additions & 1 deletion docs/data_collection/api/datacollection_filter_method.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,14 @@ grid.data.filter({

@descr:

**Related sample**: [Data. Filter](https://snippet.dhtmlx.com/csiwq3kj)

### Combining filters

Unless `config.add` is set, the method replaces the currently applied filters; calling it without a rule at all drops all non-permanent filters and restores the unfiltered order. Permanent filters are the exception: they always survive and are reapplied first. The new rule then narrows their result further, so an item remains in the result only if it matches both the permanent filter and the new rule.

**Related sample**: [Data. Filter](https://snippet.dhtmlx.com/csiwq3kj)
### Filtering grouped data

When data is [grouped](data_collection/api/datacollection_group_method.md), DataCollection matches the rule against the data items only. It never checks group headers and summary rows against the rule, so a filtering function never receives a `$group` or a `$groupSummary` item. A group stays as long as any of its items match the rule, and DataCollection recalculates the [counters and aggregated values](data_collection/api/datacollection_group_method.md#group-counters-and-aggregates) of the groups that remain.


67 changes: 65 additions & 2 deletions docs/data_collection/api/datacollection_group_method.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ interface IGroupOrder {
type TGroupOrder = string | TGroupOrderFunc | IGroupOrder;
interface IGroupConfig {
showMissed?: boolean | string; // true by default
showEmptyGroups?: boolean; // false by default
field?: string; // "group" by default
}

Expand All @@ -48,7 +49,7 @@ group(order: TGroupOrder[], config?: IGroupConfig): void;
</tr>
<tr>
<td><b>config</b></td>
<td>(<i>object</i>) optional, the configuration of data grouping. The configuration object may include the following properties:<ul><li><b>`showMissed?: boolean | string`</b> - optional, specifies whether the elements that don't have the field for grouping should be displayed, *true* by default<ul><li>if set to *true*, the rows that don't have values for grouping are rendered row by row after all the data</li><li>if a *string* value is set, e.g. "Missed", the rows that don't have values for grouping are rendered as a separate group the name of which will have the specified string value. This group will be rendered as the last one</li><li>if set to *false*, the rows that don't suit the grouping criteria won't be rendered</li></ul></li><li><b>`field?: string`</b> - optional, the group field name, *"group"* by default</li></ul></td>
<td>(<i>object</i>) optional, the configuration of data grouping. The configuration object may include the following properties:<ul><li><b>`showMissed?: boolean | string`</b> - optional, specifies whether the elements that don't have the field for grouping should be displayed, *true* by default<ul><li>if set to *true*, the rows that don't have values for grouping are rendered row by row after all the data</li><li>if a *string* value is set, e.g. "Missed", the rows that don't have values for grouping are rendered as a separate group the name of which will have the specified string value. This group will be rendered as the last one</li><li>if set to *false*, the rows that don't suit the grouping criteria won't be rendered</li></ul></li><li><b>`showEmptyGroups?: boolean`</b> - optional, specifies whether a group that loses all its items to filtering stays in the collection, *false* by default<ul><li>if set to *false*, such a group leaves the collection together with its summary row and its nested groups, so `map()` skips it and `getLength()` leaves it out. A `resetFilter()` call brings it back</li><li>if set to *true*, such a group stays with the `$count: 0` value and emptied aggregates: the "sum" and "count" aggregations give *0*, while "avg", "min" and "max" give *null*</li></ul></li><li><b>`field?: string`</b> - optional, the group field name, *"group"* by default</li></ul></td>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Добавлено в config:

Image

</tr>
</tbody>
</table>
Expand Down Expand Up @@ -130,4 +131,66 @@ grid.data.group(["city"], {

@descr:

@changelog: added in v9.0
## Group counters and aggregates

Group headers follow the data they hold. DataCollection recalculates them after every change of the collection content, that is after the [`filter()`](data_collection/api/datacollection_filter_method.md), [`resetFilter()`](data_collection/api/datacollection_resetfilter_method.md), [`add()`](data_collection/api/datacollection_add_method.md), [`remove()`](data_collection/api/datacollection_remove_method.md), [`update()`](data_collection/api/datacollection_update_method.md) and [`parse()`](data_collection/api/datacollection_parse_method.md) methods.

:::note
The same applies to TreeCollection, and thus to Grid in the [TreeGrid mode](grid/treegrid_mode.md): a counter covers the whole subtree of a header row, and an emptied header row disappears together with everything below it.
:::

Recalculation needs no configuration, it happens on every data change while the collection is grouped:

~~~jsx
const data = new dhx.DataCollection();
data.parse(dataset);

data.group([{ by: "status", map: { total: ["price", "sum"] }, summary: "bottom" }]);

// the header row of the "wip" group, which holds two items with the total of 50
const wip = data.map(item => item).find(item => item.$group);

wip.$count; // 2
wip.$totalCount; // 2
wip.total; // 50

data.filter({
by: "price",
match: 30,
compare: (value, match) => Number(value) >= Number(match)
});

wip.$count; // 1
wip.$totalCount; // 2, the unfiltered number of items
wip.total; // 30, recomputed over the items that are left
data.getItem(`${wip.id}:summary`).total; // 30, the summary row follows

data.resetFilter();
wip.$count; // 2
~~~

### Counters of a group

A group header row carries the following service properties:

- `$count` - the number of data items that the group currently holds. For a nested grouping it is the size of the whole subtree of the group. Nested headers and summary rows don't count as data
- `$totalCount` - the number of data items that the group holds ignoring the active filters. It equals `$count` when no filter is active

### Aggregated fields

DataCollection recomputes every field listed in the `map` object of a grouping level over the items that are left, on the header row and on the group summary row that the `summary` property adds alike, so both rows show the same values.

### Filtering grouped data

DataCollection matches a filtering rule against the data items only, so a filtering function never receives a `$group` or a `$groupSummary` item. A group stays as long as any of its items match the rule, and a group that loses all of them leaves the collection together with its summary row and its nested groups. [`map()`](data_collection/api/datacollection_map_method.md) skips such a group and [`getLength()`](data_collection/api/datacollection_getlength_method.md) leaves it out, unless you pass the `showEmptyGroups: true` config to the method, and [`resetFilter()`](data_collection/api/datacollection_resetfilter_method.md) brings it back either way.

### Removing a group

A group emptied by [`remove()`](data_collection/api/datacollection_remove_method.md) has no filter to bring it back, so it leaves the collection for good, its summary row included, and [`getItem()`](data_collection/api/datacollection_getitem_method.md) returns *undefined* for the id of its header.

**Related sample**: [Grid. Grouping counters and empty groups](https://snippet.dhtmlx.com/f4a5voun?mode=wide)

@changelog:
- As of v9.4, DataCollection recalculates the counters and aggregated values of group headers after every change of the collection content
- The `showEmptyGroups` property of the `config` parameter is added in v9.4
- Added in v9.0
2 changes: 2 additions & 0 deletions docs/data_collection/api/datacollection_parse_method.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,6 @@ Please note that if you specify the `id` fields in the data collection, their va

The method resets the applied sorting and filtering: the sorting is dropped, and so are all the filters except those applied with `permanent: true`, which are reapplied to the new data.

When data is [grouped](data_collection/api/datacollection_group_method.md), DataCollection recalculates the [counters and aggregated values](data_collection/api/datacollection_group_method.md#group-counters-and-aggregates) of the groups over the new data.

**Related sample**: [Data. Parse](https://snippet.dhtmlx.com/0zrxtmvi)
6 changes: 4 additions & 2 deletions docs/data_collection/api/datacollection_remove_method.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ component.data.remove(["2", "4"]);

@descr:

**Related sample**: [Data. Remove](https://snippet.dhtmlx.com/ugdlqgp5)
When data is [grouped](data_collection/api/datacollection_group_method.md), passing the id of a group header removes the whole group: the header itself, the items of the group, its summary row and its nested groups. DataCollection recalculates the [counters and aggregated values](data_collection/api/datacollection_group_method.md#group-counters-and-aggregates) of the groups that remain.

**Related article**: [Controls and operations](window/customization.md#controls-and-operations)

[comment]: # (@related:window/customization.md#controls-and-operations)
**Related sample**: [Data. Remove](https://snippet.dhtmlx.com/ugdlqgp5)
2 changes: 2 additions & 0 deletions docs/data_collection/api/datacollection_resetfilter_method.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ component.data.resetFilter({ id: "filter_id" });

@descr:

When data is [grouped](data_collection/api/datacollection_group_method.md), DataCollection recalculates the [counters and aggregated values](data_collection/api/datacollection_group_method.md#group-counters-and-aggregates) of the groups over the restored data and brings back the groups that the filter left with no items.

**Related sample**:
- [Data. ResetFilter](https://snippet.dhtmlx.com/jg8wxfvc)
- [Grid. ResetFilter](https://snippet.dhtmlx.com/15trblk2)
6 changes: 4 additions & 2 deletions docs/data_collection/api/datacollection_update_method.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ itemsForUpdate.forEach((item, index) => {
});
~~~

**Related sample**: [Data. Update](https://snippet.dhtmlx.com/4g90gi6b)
When data is [grouped](data_collection/api/datacollection_group_method.md), DataCollection recalculates the [counters and aggregated values](data_collection/api/datacollection_group_method.md#group-counters-and-aggregates) of the groups over the resulting data.

**Related article**: [Controls and operations](window/customization.md#controls-and-operations)

[comment]: # (@related:window/customization.md#controls-and-operations)
**Related sample**: [Data. Update](https://snippet.dhtmlx.com/4g90gi6b)
2 changes: 2 additions & 0 deletions docs/grid/api/grid_getsummary_method.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ console.log(columnSummary); //{ totalPopulation: 1000000, avgAge: 28 } - the val
- When called without parameters, the method returns an object with the calculated values defined in the configuration of the component.
- When the `id` parameter is passed to the method, it returns an object with the calculated values defined in the column's configuration together with the calculated values defined in the component's configuration.

In a grid with [grouped data](grid/usage.md#grouping-data), the method calculates the returned values over the data rows only: the group header rows and the group summary rows don't count as data.

**Related article:** [Getting the summary object](grid/configuration.md#getting-the-summary-object)

**Related API**: [summary](grid/api/grid_summary_config.md)
Expand Down
19 changes: 17 additions & 2 deletions docs/grid/api/grid_group_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ Note that when you initialize Grid with the `group` configuration property, the

#### Usage

~~~jsx {22}
~~~jsx {25}
type TAggregate = "sum" | "count" | "min" | "max" | "avg" | string;

interface IGroupOrder {
by: string | ((row: IRow) => string);
map?: { [field: string]: [string, TAggregate] | ((row: IRow[]) => string | number) };
summary?: "top" | "bottom";
}
Expand All @@ -33,6 +34,8 @@ interface IGroup {
panelHeight: number; // 40 by default
hideableColumns?: boolean; // true by default
showMissed?: boolean | string; // true by default
showEmptyGroups?: boolean; // false by default
counter?: boolean | ((row: IRow) => string); // true by default
fields?: { [colId: string]: IGroupOrder };
order?: IGroupOrderItem[];
column?: string | ICol;
Expand Down Expand Up @@ -60,6 +63,13 @@ You can find the detailed description of the `group` object properties with exam
- if set to *true*, the rows that don't have values for grouping are rendered row by row after all the data
- if a *string* value is set, e.g. "Missed", the rows that don't have values for grouping are rendered as a separate group the name of which will have the specified string value. This group will be rendered as the last one
- if set to *false*, the rows that don't suit the grouping criteria won't be rendered
- `showEmptyGroups` - (optional) specifies whether a group that loses all its rows to filtering stays in the grid, *false* by default
- if set to *false*, such a group leaves the view together with its summary row and its nested groups, and [`resetFilter()`](data_collection/api/datacollection_resetfilter_method.md) brings it back
- if set to *true*, such a group remains visible with the `$count: 0` value and emptied aggregates: the "sum" and "count" aggregations give *0*, while "avg", "min" and "max" give *null*, as described in the [Data calculation functions](helpers/data_calculation_functions.md#aggregating-an-empty-set-of-items) guide
- `counter` - (optional) defines the text rendered next to the group name in the column with grouped data, *true* by default
- if set to *true*, Grid renders the current number of rows of the group in brackets, e.g. *(2)*
- if set to *false*, Grid renders only the group name
- if set to a *function*, it takes the group header row as a parameter and returns the string to render. Grid inserts the returned value as HTML, so it may contain markup; an empty string renders no counter. The row gives access to the `$count`, `$totalCount` and `$by` service properties and to every aggregated field of the `map` object of the level
- `fields` - (optional) predefines an extended configuration for data grouping by certain columns, by setting the rules of aggregation and rendering of the results. The attributes of the `fields` object correspond to the ids of columns for which the aggregation rules and the order of results are being configured. The configuration of a column is defined by the `IGroupOrder` object that has the following properties:
- `map` - (optional) an object for data aggregation in a group, where the keys are field names, and the values can be:
- a tuple `[string, TAggregate]` that specifies the field and the aggregation type ("sum", "count", "min", "max", "avg") from the [`dhx.methods`](helpers/data_calculation_functions.md) helper
Expand All @@ -69,6 +79,7 @@ You can find the detailed description of the `group` object properties with exam
- a string that represents a grouping field
- a function `((row: IRow) => string)` for dynamic defining of a group
- an `IGroupOrder` object that has the following properties:
- `by` - the field name or a function `((row: IRow) => string)` for user-defined grouping
- `map` - (optional) an object for data aggregation in a group, where the keys are field names, and the values can be:
- a tuple `[string, TAggregate]` that specifies the field and the aggregation type ("sum", "count", "min", "max", "avg") from the `dhx.methods` helper
- a user-defined aggregation function `((row: IRow[]) => string | number)`
Expand All @@ -94,4 +105,8 @@ const grid = new dhx.Grid("grid_container", {

**Related article**: [Grouping data](grid/usage.md#grouping-data)

@changelog: added in v9.0
**Related sample**: [Grid. Grouping counters and empty groups](https://snippet.dhtmlx.com/f4a5voun?mode=wide)

@changelog:
- The `counter` and `showEmptyGroups` properties are added in v9.4
- Added in v9.0
8 changes: 8 additions & 0 deletions docs/grid/api/grid_summary_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,5 +86,13 @@ console.log(summary); // { totalPopulation: 1000000, totalArea: 50000, density:

**Related API**: [getSummary()](grid/api/grid_getsummary_method.md)

#### Summaries in a grouped grid

In a grid with [grouped data](grid/usage.md#grouping-data), Grid calculates the summaries over the data rows only: the group header rows and the group summary rows don't count as data.

#### Summaries of an empty grid

When a grid has no rows, Grid calls the built-in functors with an empty set of rows: the "sum" and "count" functors give *0*, while "avg", "min" and "max" give *null*, which renders as an empty value. Check the details in the [Data calculation functions](helpers/data_calculation_functions.md#aggregating-an-empty-set-of-items) guide.

@changelog:
- Added in v9.0
4 changes: 4 additions & 0 deletions docs/grid/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -1212,6 +1212,10 @@ It is also possible to [get the object with the calculated values](#getting-the-
Use the [`dhx.methods`](helpers/data_calculation_functions.md) helper to define the default statistical functions and to create custom functions for data calculation while creating the summary list.
:::

:::note
In a grid with [grouped data](grid/usage.md#grouping-data), the summaries are calculated over the data rows only: the group header rows and the group summary rows aren't counted as data.
:::

### Column summary

To form a summary list that will be available at the column's level only, you should use the [`summary`](grid/api/api_gridcolumn_properties.md) configuration option of the column. The `summary` configuration option of a column can be initialized either as an *object* or as a *string*. As an object it contains calculated values set as *key:value* pairs, where the *keys* are the field names and *values* can be:
Expand Down
Loading