@progress/kendo-angular-grid 19.2.0-develop.1 → 19.2.0-develop.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -532,6 +532,9 @@ const isMultipleRangesEnabled = (selectableSettings) => {
532
532
  */
533
533
  const calcRowHeight = (tableBody) => {
534
534
  let result = 0;
535
+ if (!isDocumentAvailable()) {
536
+ return result;
537
+ }
535
538
  if (tableBody) {
536
539
  const row = tableBody.insertRow(0);
537
540
  const cell = row.insertCell(0);
@@ -865,7 +868,7 @@ class ContextService {
865
868
  topToolbarNavigation;
866
869
  bottomToolbarNavigation;
867
870
  navigable;
868
- groupBindingDirective;
871
+ dataBindingDirective;
869
872
  constructor(renderer, localization) {
870
873
  this.renderer = renderer;
871
874
  this.localization = localization;
@@ -14136,7 +14139,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
14136
14139
  }] } });
14137
14140
 
14138
14141
  /**
14139
- * Represents a directive that manages keyboard navigation for a column menu item. [See example](slug:columnmenu_grid#customizing-the-content).
14142
+ * Represents a directive that manages keyboard navigation for a column menu item ([see example](slug:columnmenu_grid#customizing-the-content)).
14140
14143
  *
14141
14144
  * @example
14142
14145
  * ```html
@@ -16672,7 +16675,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
16672
16675
  */
16673
16676
  class CellSelectionAggregateService {
16674
16677
  ctx;
16675
- dataChanges;
16676
16678
  columnInfoService;
16677
16679
  selectedItems = [];
16678
16680
  groupedAggregates = { dates: [], numbers: [], booleans: [] };
@@ -16688,9 +16690,8 @@ class CellSelectionAggregateService {
16688
16690
  latest: null
16689
16691
  };
16690
16692
  sub = new Subscription();
16691
- constructor(ctx, dataChanges, columnInfoService) {
16693
+ constructor(ctx, columnInfoService) {
16692
16694
  this.ctx = ctx;
16693
- this.dataChanges = dataChanges;
16694
16695
  this.columnInfoService = columnInfoService;
16695
16696
  }
16696
16697
  ngOnDestroy() {
@@ -16851,12 +16852,12 @@ class CellSelectionAggregateService {
16851
16852
  this.aggregates['isFalse'] = this.aggregates['isTrue'] = null;
16852
16853
  this.aggregates['earliest'] = this.aggregates['latest'] = null;
16853
16854
  }
16854
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CellSelectionAggregateService, deps: [{ token: ContextService }, { token: LocalDataChangesService }, { token: ColumnInfoService }], target: i0.ɵɵFactoryTarget.Injectable });
16855
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CellSelectionAggregateService, deps: [{ token: ContextService }, { token: ColumnInfoService }], target: i0.ɵɵFactoryTarget.Injectable });
16855
16856
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CellSelectionAggregateService });
16856
16857
  }
16857
16858
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CellSelectionAggregateService, decorators: [{
16858
16859
  type: Injectable
16859
- }], ctorParameters: function () { return [{ type: ContextService }, { type: LocalDataChangesService }, { type: ColumnInfoService }]; } });
16860
+ }], ctorParameters: function () { return [{ type: ContextService }, { type: ColumnInfoService }]; } });
16860
16861
 
16861
16862
  /**
16862
16863
  * @hidden
@@ -16985,6 +16986,8 @@ class SelectionService {
16985
16986
  if (ev.shiftKey) {
16986
16987
  ev.rangeStartRow = { dataItem: this.lastSelectionData, index: this.lastSelectionStartIndex };
16987
16988
  ev.rangeEndRow = { dataItem: item.data, index: item.index };
16989
+ this.lastSelectionData = item.data;
16990
+ this.lastSelectionStartIndex = item.index;
16988
16991
  }
16989
16992
  this.syncCurrentSelection(ev);
16990
16993
  this.changes.emit(ev);
@@ -17073,13 +17076,14 @@ class SelectionService {
17073
17076
  item = iterator.next();
17074
17077
  }
17075
17078
  }
17076
- addAllTo(item, ctrlKey, preserveSelection = false) {
17079
+ addAllTo(item, ctrlKey, preserveSelection = false, shiftKey = false) {
17077
17080
  const selectedRows = [];
17078
17081
  const deselectedRows = [];
17079
17082
  const start = Math.min(this.lastSelectionStartIndex, item.index);
17080
17083
  const end = Math.max(this.lastSelectionStartIndex, item.index);
17081
17084
  const iterator = this.getIterator();
17082
17085
  let next = iterator.next();
17086
+ let selectedItem;
17083
17087
  while (!next.done) {
17084
17088
  if (next.value && next.value.type === "data") {
17085
17089
  const idx = next.value.index;
@@ -17090,6 +17094,9 @@ class SelectionService {
17090
17094
  if ((idx >= start && idx <= end) && !this.isSelected(idx) && !this.nonSelectableRows.has(idx)) {
17091
17095
  selectedRows.push(rowArgs);
17092
17096
  }
17097
+ if (idx === item.index && !this.nonSelectableRows.has(idx)) {
17098
+ selectedItem = rowArgs;
17099
+ }
17093
17100
  }
17094
17101
  next = iterator.next();
17095
17102
  }
@@ -17097,10 +17104,23 @@ class SelectionService {
17097
17104
  const nonSelectableRows = this.currentSelection.filter(i => this.nonSelectableRows.has(i.index));
17098
17105
  deselectedRows.push(...nonSelectableRows);
17099
17106
  }
17100
- return {
17101
- deselectedRows: deselectedRows,
17102
- selectedRows: selectedRows
17107
+ const selectionEvent = {
17108
+ deselectedRows,
17109
+ selectedRows
17103
17110
  };
17111
+ if (shiftKey && selectedItem) {
17112
+ selectionEvent.rangeStartRow = {
17113
+ dataItem: this.lastSelectionData,
17114
+ index: this.lastSelectionStartIndex
17115
+ };
17116
+ selectionEvent.rangeEndRow = {
17117
+ dataItem: selectedItem.dataItem,
17118
+ index: selectedItem.index
17119
+ };
17120
+ this.lastSelectionData = selectedItem.dataItem;
17121
+ this.lastSelectionStartIndex = selectedItem.index;
17122
+ }
17123
+ return selectionEvent;
17104
17124
  }
17105
17125
  updateAll(selectAllChecked) {
17106
17126
  this.selectAllChecked = selectAllChecked;
@@ -19089,7 +19109,7 @@ class SelectionCheckboxDirective {
19089
19109
  const ctrlKey = event.ctrlKey || event.metaKey;
19090
19110
  if (event.shiftKey && this.selectionService.options.mode === 'multiple') {
19091
19111
  const item = { index: this.itemIndex };
19092
- ev = this.selectionService.addAllTo(item, ctrlKey);
19112
+ ev = this.selectionService.addAllTo(item, ctrlKey, false, event.shiftKey);
19093
19113
  }
19094
19114
  else {
19095
19115
  ev = this.selectionService.toggleByIndex(this.itemIndex);
@@ -21194,8 +21214,8 @@ const packageMetadata = {
21194
21214
  productName: 'Kendo UI for Angular',
21195
21215
  productCode: 'KENDOUIANGULAR',
21196
21216
  productCodes: ['KENDOUIANGULAR'],
21197
- publishDate: 1750784754,
21198
- version: '19.2.0-develop.1',
21217
+ publishDate: 1751281289,
21218
+ version: '19.2.0-develop.10',
21199
21219
  licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
21200
21220
  };
21201
21221
 
@@ -23576,7 +23596,8 @@ class ListComponent {
23576
23596
  if (this.virtualColumns && (!this.viewportColumns || this.viewportWidthChange())) {
23577
23597
  this.updateViewportColumns();
23578
23598
  }
23579
- if (this.isVirtual && this.ctx.grid && !this.ctx.grid.pageSize) {
23599
+ const shouldCalculatePageSize = isDocumentAvailable() && this.isVirtual && this.ctx.grid && !this.ctx.grid.pageSize;
23600
+ if (shouldCalculatePageSize) {
23580
23601
  const calculatedPageSize = this.calcVirtualPageSize();
23581
23602
  if (calculatedPageSize > 0) {
23582
23603
  this.ngZone.onMicrotaskEmpty.pipe(take(1)).subscribe(() => {
@@ -23658,6 +23679,36 @@ class ListComponent {
23658
23679
  args.preventDefault();
23659
23680
  }
23660
23681
  }
23682
+ updateViewportColumns(range) {
23683
+ const columns = this.columns.nonLockedLeafColumns.toArray();
23684
+ // eslint-disable-next-line prefer-const
23685
+ let { startIdx, endIdx, offset } = range || this.calculateViewportColumns();
23686
+ const start = Math.max(0, startIdx - bufferSize);
23687
+ const end = Math.min(endIdx + bufferSize, columns.length - 1);
23688
+ if (start < startIdx) {
23689
+ for (let idx = startIdx - 1; idx >= start; idx--) {
23690
+ offset -= columns[idx].width;
23691
+ }
23692
+ }
23693
+ let currentColumns = columns.slice(start, end + 1);
23694
+ this.viewportColumnsWidth = currentColumns.reduce((total, column) => total + column.width, 0);
23695
+ const stickyBeforeStart = columns.slice(0, start).filter(c => c.sticky && !currentColumns.some(col => col === c));
23696
+ const stickyAfterEnd = columns.slice(end, columns.length).filter(c => c.sticky && !currentColumns.some(col => col === c));
23697
+ currentColumns = [...stickyBeforeStart, ...currentColumns, ...stickyAfterEnd];
23698
+ if (start > 0) {
23699
+ const offsetColumn = new ColumnBase();
23700
+ offsetColumn.width = offset;
23701
+ currentColumns.unshift(offsetColumn);
23702
+ }
23703
+ this.viewportColumns = new QueryList();
23704
+ this.viewportColumns.reset(currentColumns);
23705
+ this.columnsStartIdx = start;
23706
+ this.columnsEndIdx = end;
23707
+ this.columnInfo.columnRangeChange.emit({ start, end, offset });
23708
+ if (!range) {
23709
+ this.updateColumnViewport(startIdx, endIdx);
23710
+ }
23711
+ }
23661
23712
  detailExpand({ index, expand }) {
23662
23713
  if (expand) {
23663
23714
  this.rowHeightService.expandDetail(index);
@@ -23883,36 +23934,6 @@ class ListComponent {
23883
23934
  })
23884
23935
  .forEach(setHeight(this.renderer));
23885
23936
  }
23886
- updateViewportColumns(range) {
23887
- const columns = this.columns.nonLockedLeafColumns.toArray();
23888
- // eslint-disable-next-line prefer-const
23889
- let { startIdx, endIdx, offset } = range || this.calculateViewportColumns();
23890
- const start = Math.max(0, startIdx - bufferSize);
23891
- const end = Math.min(endIdx + bufferSize, columns.length - 1);
23892
- if (start < startIdx) {
23893
- for (let idx = startIdx - 1; idx >= start; idx--) {
23894
- offset -= columns[idx].width;
23895
- }
23896
- }
23897
- let currentColumns = columns.slice(start, end + 1);
23898
- this.viewportColumnsWidth = currentColumns.reduce((total, column) => total + column.width, 0);
23899
- const stickyBeforeStart = columns.slice(0, start).filter(c => c.sticky && !currentColumns.some(col => col === c));
23900
- const stickyAfterEnd = columns.slice(end, columns.length).filter(c => c.sticky && !currentColumns.some(col => col === c));
23901
- currentColumns = [...stickyBeforeStart, ...currentColumns, ...stickyAfterEnd];
23902
- if (start > 0) {
23903
- const offsetColumn = new ColumnBase();
23904
- offsetColumn.width = offset;
23905
- currentColumns.unshift(offsetColumn);
23906
- }
23907
- this.viewportColumns = new QueryList();
23908
- this.viewportColumns.reset(currentColumns);
23909
- this.columnsStartIdx = start;
23910
- this.columnsEndIdx = end;
23911
- this.columnInfo.columnRangeChange.emit({ start, end, offset });
23912
- if (!range) {
23913
- this.updateColumnViewport(startIdx, endIdx);
23914
- }
23915
- }
23916
23937
  handleColumnScroll() {
23917
23938
  const container = this.container.nativeElement;
23918
23939
  const scrollLeft = container.scrollLeft;
@@ -27624,6 +27645,538 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
27624
27645
  args: [GroupToolbarToolComponent]
27625
27646
  }] } });
27626
27647
 
27648
+ /**
27649
+ * A directive that handles in-memory data operations like [paging]({% slug paging_grid %}),
27650
+ * [sorting]({% slug sorting_grid %}), and [grouping]({% slug grouping_grid %}).
27651
+ *
27652
+ * Use this directive with local data and enable the Grid data operations with minimal configuration.
27653
+ * ([More information and examples]({% slug local_data_grid %}#toc-using-the-data-binding-directive)).
27654
+ *
27655
+ * @example
27656
+ * ```html
27657
+ * <kendo-grid [kendoGridBinding]="gridData"></kendo-grid>
27658
+ * ```
27659
+ * @remarks
27660
+ * Applied to: {@link GridComponent}.
27661
+ */
27662
+ class DataBindingDirective {
27663
+ grid;
27664
+ changeDetector;
27665
+ localDataChangesService;
27666
+ rowReorderService;
27667
+ /**
27668
+ * Sets the number of records to skip in the Grid.
27669
+ *
27670
+ * @default 0
27671
+ */
27672
+ set skip(value) {
27673
+ if (!isPresent(value)) {
27674
+ value = 0;
27675
+ }
27676
+ this.grid.skip = this.state.skip = value;
27677
+ if (this.rowReorderService) {
27678
+ this.rowReorderService.skip = value;
27679
+ }
27680
+ }
27681
+ /**
27682
+ * Sets the sort descriptors for the Grid data.
27683
+ *
27684
+ */
27685
+ set sort(value) {
27686
+ this.grid.sort = this.state.sort = value;
27687
+ }
27688
+ /**
27689
+ * Sets the filter descriptor for the Grid data.
27690
+ *
27691
+ */
27692
+ set filter(value) {
27693
+ this.grid.filter = this.state.filter = value;
27694
+ }
27695
+ /**
27696
+ * Sets the page size for the Grid pager.
27697
+ *
27698
+ */
27699
+ set pageSize(value) {
27700
+ this.grid.pageSize = this.state.take = value;
27701
+ }
27702
+ /**
27703
+ * Sets the group descriptors for the Grid data.
27704
+ *
27705
+ */
27706
+ set group(value) {
27707
+ this.grid.group = this.state.group = value;
27708
+ }
27709
+ /**
27710
+ * Sets the data array for the Grid.
27711
+ *
27712
+ */
27713
+ set data(value) {
27714
+ this.originalData = value || [];
27715
+ if (this.localDataChangesService) {
27716
+ this.localDataChangesService.data = value;
27717
+ }
27718
+ this.dataChanged = true;
27719
+ }
27720
+ state = {
27721
+ skip: 0
27722
+ };
27723
+ originalData = [];
27724
+ dataChanged;
27725
+ stateChangeSubscription;
27726
+ dataChangedSubscription;
27727
+ rowReorderSubscription;
27728
+ constructor(grid, changeDetector, localDataChangesService, rowReorderService, ctx) {
27729
+ this.grid = grid;
27730
+ this.changeDetector = changeDetector;
27731
+ this.localDataChangesService = localDataChangesService;
27732
+ this.rowReorderService = rowReorderService;
27733
+ if (localDataChangesService) {
27734
+ this.dataChangedSubscription = this.localDataChangesService.changes.subscribe(this.rebind.bind(this));
27735
+ }
27736
+ ctx && (ctx.dataBindingDirective = this);
27737
+ }
27738
+ /**
27739
+ * @hidden
27740
+ */
27741
+ ngOnInit() {
27742
+ this.applyState(this.state);
27743
+ this.stateChangeSubscription = this.grid
27744
+ .dataStateChange
27745
+ .subscribe(this.onStateChange.bind(this));
27746
+ if (this.rowReorderService) {
27747
+ this.rowReorderSubscription = this.grid
27748
+ .rowReorder
27749
+ .subscribe(this.onRowReorder.bind(this));
27750
+ }
27751
+ }
27752
+ /**
27753
+ * @hidden
27754
+ */
27755
+ ngOnDestroy() {
27756
+ if (this.stateChangeSubscription) {
27757
+ this.stateChangeSubscription.unsubscribe();
27758
+ }
27759
+ if (this.dataChangedSubscription) {
27760
+ this.dataChangedSubscription.unsubscribe();
27761
+ }
27762
+ if (this.rowReorderSubscription) {
27763
+ this.rowReorderSubscription.unsubscribe();
27764
+ }
27765
+ }
27766
+ /**
27767
+ * @hidden
27768
+ */
27769
+ ngOnChanges(changes) {
27770
+ if (anyChanged(["pageSize", "skip", "sort", "group", "filter"], changes)) {
27771
+ this.rebind();
27772
+ }
27773
+ }
27774
+ ngDoCheck() {
27775
+ if (this.dataChanged) {
27776
+ this.updateGridData();
27777
+ }
27778
+ }
27779
+ /**
27780
+ * @hidden
27781
+ */
27782
+ onStateChange(state) {
27783
+ this.applyState(state);
27784
+ this.rebind();
27785
+ }
27786
+ /**
27787
+ * @hidden
27788
+ */
27789
+ onRowReorder(ev) {
27790
+ this.rowReorderService.reorderRows(ev, this.originalData);
27791
+ this.rebind();
27792
+ }
27793
+ /**
27794
+ * @hidden
27795
+ */
27796
+ rebind() {
27797
+ this.data = this.originalData;
27798
+ this.updateGridData();
27799
+ this.notifyDataChange();
27800
+ }
27801
+ /**
27802
+ * Notifies the Grid that its data has changed.
27803
+ */
27804
+ notifyDataChange() {
27805
+ this.grid.onDataChange();
27806
+ if (this.changeDetector) {
27807
+ this.changeDetector.markForCheck();
27808
+ }
27809
+ }
27810
+ process(state) {
27811
+ if (this.grid.isVirtual && (!isPresent(state.take) || state.take === 0)) {
27812
+ return {
27813
+ data: [],
27814
+ total: this.originalData?.length || 0
27815
+ };
27816
+ }
27817
+ return process(this.originalData, state);
27818
+ }
27819
+ applyState({ skip, take, sort, group, filter }) {
27820
+ this.skip = skip;
27821
+ this.pageSize = take;
27822
+ this.sort = sort;
27823
+ this.group = group;
27824
+ this.filter = filter;
27825
+ }
27826
+ updateGridData() {
27827
+ this.grid.data = this.process(this.state);
27828
+ this.grid.updateNavigationMetadata();
27829
+ this.dataChanged = false;
27830
+ }
27831
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DataBindingDirective, deps: [{ token: GridComponent }, { token: i0.ChangeDetectorRef }, { token: LocalDataChangesService }, { token: RowReorderService }, { token: ContextService }], target: i0.ɵɵFactoryTarget.Directive });
27832
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: DataBindingDirective, isStandalone: true, selector: "[kendoGridBinding]", inputs: { skip: "skip", sort: "sort", filter: "filter", pageSize: "pageSize", group: "group", data: ["kendoGridBinding", "data"] }, exportAs: ["kendoGridBinding"], usesOnChanges: true, ngImport: i0 });
27833
+ }
27834
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DataBindingDirective, decorators: [{
27835
+ type: Directive,
27836
+ args: [{
27837
+ selector: '[kendoGridBinding]',
27838
+ exportAs: 'kendoGridBinding',
27839
+ standalone: true
27840
+ }]
27841
+ }], ctorParameters: function () { return [{ type: GridComponent }, { type: i0.ChangeDetectorRef }, { type: LocalDataChangesService }, { type: RowReorderService }, { type: ContextService }]; }, propDecorators: { skip: [{
27842
+ type: Input
27843
+ }], sort: [{
27844
+ type: Input
27845
+ }], filter: [{
27846
+ type: Input
27847
+ }], pageSize: [{
27848
+ type: Input
27849
+ }], group: [{
27850
+ type: Input
27851
+ }], data: [{
27852
+ type: Input,
27853
+ args: ["kendoGridBinding"]
27854
+ }] } });
27855
+
27856
+ const hasGroups = (items) => items && items.length && items[0].field && items[0].items;
27857
+ const groupDescriptorsPresent = (descriptors) => isPresent(descriptors) && descriptors.length > 0;
27858
+ const processGroups = (data, state) => process(data, state).data;
27859
+ const removeParentDescriptors = (parents, owner) => g => g.field !== owner.field && !parents.some(y => y.field === g.field);
27860
+ const findGroup = (groupIndex, groups) => {
27861
+ const parents = [];
27862
+ return {
27863
+ group: groupIndex.split("_").reduce((acc, x) => {
27864
+ const idx = parseInt(x, 10);
27865
+ if (acc.items) {
27866
+ parents.push(acc);
27867
+ return acc.items[idx];
27868
+ }
27869
+ return isArray(acc) ? acc[idx] : acc;
27870
+ }, groups),
27871
+ parents
27872
+ };
27873
+ };
27874
+ const findChildren = (data, parents) => {
27875
+ const filters = parents.map(p => ({ field: p.field, operator: "eq", value: p.value }));
27876
+ return filterBy(data, {
27877
+ filters: filters,
27878
+ logic: "and"
27879
+ });
27880
+ };
27881
+ /**
27882
+ * @hidden
27883
+ */
27884
+ const count = (groups, includeFooters = false) => (groups.reduce((acc, group) => {
27885
+ if (!group.skipHeader) {
27886
+ acc++;
27887
+ }
27888
+ if (group.items) {
27889
+ const children = count(group.items, includeFooters);
27890
+ if (includeFooters && children && !group.hideFooter) {
27891
+ acc++;
27892
+ }
27893
+ acc += children;
27894
+ }
27895
+ return acc;
27896
+ }, 0));
27897
+ /**
27898
+ * @hidden
27899
+ */
27900
+ const noDescriptors = (descriptors) => !isPresent(descriptors) || !descriptors.length;
27901
+ /**
27902
+ * @hidden
27903
+ */
27904
+ const slice = (groups, skip, take, includeFooters = false) => {
27905
+ if (!isPresent(take)) {
27906
+ return groups;
27907
+ }
27908
+ const result = [];
27909
+ for (let idx = 0, length = groups.length; idx < length; idx++) {
27910
+ if (take <= 0) {
27911
+ break;
27912
+ }
27913
+ const group = groups[idx];
27914
+ const groupItems = group.items;
27915
+ let itemCount = count(groupItems, includeFooters);
27916
+ if (includeFooters && groupItems.length) {
27917
+ itemCount++;
27918
+ }
27919
+ const skipHeader = skip > 0;
27920
+ if (skip) {
27921
+ skip--;
27922
+ if (itemCount && skip >= itemCount) {
27923
+ skip -= itemCount;
27924
+ continue;
27925
+ }
27926
+ }
27927
+ if (!skipHeader || itemCount) {
27928
+ const items = [];
27929
+ let hideFooter = true;
27930
+ if (!skipHeader) {
27931
+ take--;
27932
+ }
27933
+ if (take) {
27934
+ if (hasGroups(groupItems)) {
27935
+ const children = slice(groupItems, skip, take, includeFooters);
27936
+ items.push(...children);
27937
+ take -= count(children, includeFooters);
27938
+ }
27939
+ else {
27940
+ items.push(...groupItems.slice(skip, Math.min(skip + take, groupItems.length)));
27941
+ take -= items.length;
27942
+ }
27943
+ if (take && includeFooters) {
27944
+ hideFooter = false;
27945
+ take--;
27946
+ }
27947
+ skip = 0;
27948
+ }
27949
+ result.push({
27950
+ aggregates: group.aggregates,
27951
+ field: group.field,
27952
+ hideFooter,
27953
+ items,
27954
+ offset: idx,
27955
+ skipHeader,
27956
+ value: group.value
27957
+ });
27958
+ }
27959
+ }
27960
+ return result;
27961
+ };
27962
+ const skippedHeaders = (groupItem) => {
27963
+ let total = 0;
27964
+ while (groupItem) {
27965
+ if (groupItem.skipHeader) {
27966
+ total++;
27967
+ }
27968
+ groupItem = groupItem.items && groupItem.items[0] || null;
27969
+ }
27970
+ return total;
27971
+ };
27972
+ /**
27973
+ * A directive which encapsulates the in-memory handling of grouping with virtual scrolling.
27974
+ * @remarks
27975
+ * Applied to: {@link GridComponent}.
27976
+ */
27977
+ class GroupBindingDirective extends DataBindingDirective {
27978
+ groupsService;
27979
+ /**
27980
+ * The array of data which will be used to populate the Grid.
27981
+ */
27982
+ set kendoGridGroupBinding(value) {
27983
+ this.groups = null;
27984
+ this.grid.resetGroupsState();
27985
+ this.data = value;
27986
+ }
27987
+ /**
27988
+ * @hidden
27989
+ */
27990
+ set data(value) {
27991
+ this.originalData = value || [];
27992
+ this.dataChanged = true;
27993
+ }
27994
+ /**
27995
+ * Defines the descriptors by which the data will be sorted.
27996
+ */
27997
+ set sort(value) {
27998
+ const noCurrentDescriptors = noDescriptors(this.state.sort);
27999
+ const noIncomingDescriptors = noDescriptors(value);
28000
+ const clear = this.state.sort !== value && !(noCurrentDescriptors && noIncomingDescriptors);
28001
+ this.grid.sort = this.state.sort = value;
28002
+ if (clear) {
28003
+ this.groups = null;
28004
+ this.grid.resetGroupsState();
28005
+ }
28006
+ }
28007
+ /**
28008
+ * Defines the descriptor by which the data will be filtered.
28009
+ */
28010
+ set filter(value) {
28011
+ const clear = diffFilters(this.state.filter, value);
28012
+ if (clear) {
28013
+ this.state.filter = value;
28014
+ this.grid.filter = cloneFilters(value);
28015
+ this.groups = null;
28016
+ this.grid.resetGroupsState();
28017
+ }
28018
+ }
28019
+ /**
28020
+ * Defines the descriptors by which the data will be grouped.
28021
+ */
28022
+ set group(value) {
28023
+ // don't clear if no groups are present in previous and current value
28024
+ const groupsPresent = groupDescriptorsPresent(this.state.group) || groupDescriptorsPresent(value);
28025
+ const clear = this.state.group !== value && groupsPresent;
28026
+ this.grid.group = this.state.group = value;
28027
+ if (clear) {
28028
+ this.groups = null;
28029
+ this.grid.resetGroupsState();
28030
+ this.skip = 0;
28031
+ }
28032
+ }
28033
+ groups;
28034
+ gridSubs = new Subscription();
28035
+ constructor(changeDetector, localDataChangesService, ctxService, groupsService) {
28036
+ super(ctxService.grid, changeDetector, localDataChangesService, null, ctxService);
28037
+ this.groupsService = groupsService;
28038
+ ctxService.dataBindingDirective = this;
28039
+ }
28040
+ ngOnInit() {
28041
+ super.ngOnInit();
28042
+ this.gridSubs.add(this.grid.groupExpand.subscribe(this.groupExpand.bind(this)));
28043
+ this.gridSubs.add(this.grid.groupCollapse.subscribe(this.groupCollapse.bind(this)));
28044
+ }
28045
+ ngAfterContentInit() {
28046
+ if (isDevMode() && this.grid.isGroupExpanded) {
28047
+ throw new Error(GridConfigurationErrorMessages.groupBindingDirectives);
28048
+ }
28049
+ }
28050
+ ngOnDestroy() {
28051
+ this.gridSubs.unsubscribe();
28052
+ }
28053
+ /**
28054
+ * @hidden
28055
+ */
28056
+ toggleAll(expand) {
28057
+ this.skip = 0;
28058
+ this.grid.scrollTo({ row: 0, column: 0 });
28059
+ this.groups.forEach((gr, idx) => {
28060
+ const expanded = this.groupsService.isExpanded({
28061
+ group: gr,
28062
+ groupIndex: idx.toString(),
28063
+ parentGroup: undefined
28064
+ });
28065
+ const performToggle = (expand && !expanded) || (!expand && expanded);
28066
+ if (performToggle) {
28067
+ this.grid.groupsService.toggleRow({
28068
+ type: 'group',
28069
+ data: gr,
28070
+ index: idx.toString(),
28071
+ level: 0,
28072
+ parentGroup: undefined
28073
+ });
28074
+ this[expand ? 'groupExpand' : 'groupCollapse']({ groupIndex: idx.toString() });
28075
+ }
28076
+ });
28077
+ }
28078
+ /**
28079
+ * Collapses all expanded root level groups.
28080
+ */
28081
+ collapseAll() {
28082
+ this.toggleAll(false);
28083
+ }
28084
+ /**
28085
+ * Expands all expanded root level groups.
28086
+ */
28087
+ expandAll() {
28088
+ this.toggleAll(true);
28089
+ }
28090
+ /**
28091
+ * @hidden
28092
+ */
28093
+ groupExpand({ groupIndex }) {
28094
+ const { group, parents } = findGroup(groupIndex, this.groups);
28095
+ if (!group) {
28096
+ return;
28097
+ }
28098
+ this.groupsService.expandChildren(groupIndex);
28099
+ if (!group.items.length) {
28100
+ const descriptors = this.state.group.filter(removeParentDescriptors(parents, group));
28101
+ const children = findChildren(this.originalData, parents.concat(group));
28102
+ group.items = processGroups(children, {
28103
+ filter: this.state.filter,
28104
+ group: descriptors,
28105
+ sort: this.state.sort
28106
+ });
28107
+ }
28108
+ this.grid.data = this.dataResult(this.state.skip, this.state.take);
28109
+ }
28110
+ /**
28111
+ * @hidden
28112
+ */
28113
+ groupCollapse({ groupIndex }) {
28114
+ const { group } = findGroup(groupIndex, this.groups);
28115
+ if (group) {
28116
+ group.items = [];
28117
+ }
28118
+ else {
28119
+ return;
28120
+ }
28121
+ this.grid.data = this.dataResult(this.state.skip, this.state.take);
28122
+ }
28123
+ process(state) {
28124
+ if (state.group && state.group.length) {
28125
+ const groups = this.processGroups(state);
28126
+ this.grid.skip -= skippedHeaders(groups.data[0]);
28127
+ return groups;
28128
+ }
28129
+ else {
28130
+ this.groups = null;
28131
+ }
28132
+ return super.process(state);
28133
+ }
28134
+ processGroups(state) {
28135
+ if (!this.groups || !this.groups.length) {
28136
+ this.groups = processGroups(this.originalData, {
28137
+ filter: state.filter,
28138
+ group: state.group,
28139
+ sort: state.sort
28140
+ });
28141
+ }
28142
+ return this.dataResult(state.skip, state.take);
28143
+ }
28144
+ dataResult(skip, take) {
28145
+ const includeFooters = this.grid.showGroupFooters;
28146
+ return {
28147
+ data: slice(this.groups, skip, take, includeFooters),
28148
+ total: count(this.groups, includeFooters)
28149
+ };
28150
+ }
28151
+ applyState({ skip, take, sort, group, filter }) {
28152
+ this.skip = skip;
28153
+ this.state.take = take;
28154
+ // this.pageSize = take; // do need to update take as the process with slice correctly
28155
+ this.sort = sort;
28156
+ this.group = group;
28157
+ this.filter = filter;
28158
+ }
28159
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: GroupBindingDirective, deps: [{ token: i0.ChangeDetectorRef }, { token: LocalDataChangesService }, { token: ContextService }, { token: GroupsService }], target: i0.ɵɵFactoryTarget.Directive });
28160
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: GroupBindingDirective, isStandalone: true, selector: "[kendoGridGroupBinding]", inputs: { kendoGridGroupBinding: "kendoGridGroupBinding", sort: "sort", filter: "filter", group: "group" }, exportAs: ["kendoGridGroupBinding"], usesInheritance: true, ngImport: i0 });
28161
+ }
28162
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: GroupBindingDirective, decorators: [{
28163
+ type: Directive,
28164
+ args: [{
28165
+ selector: '[kendoGridGroupBinding]',
28166
+ exportAs: 'kendoGridGroupBinding',
28167
+ standalone: true
28168
+ }]
28169
+ }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: LocalDataChangesService }, { type: ContextService }, { type: GroupsService }]; }, propDecorators: { kendoGridGroupBinding: [{
28170
+ type: Input,
28171
+ args: ["kendoGridGroupBinding"]
28172
+ }], sort: [{
28173
+ type: Input
28174
+ }], filter: [{
28175
+ type: Input
28176
+ }], group: [{
28177
+ type: Input
28178
+ }] } });
28179
+
27627
28180
  const createControl = (source) => (acc, key) => {
27628
28181
  acc[key] = new FormControl(source[key]);
27629
28182
  return acc;
@@ -28416,10 +28969,8 @@ class GridComponent {
28416
28969
  dragTargetContainer;
28417
28970
  dropTargetContainer;
28418
28971
  dialogContainer;
28419
- /**
28420
- * @hidden
28421
- */
28422
28972
  adaptiveRenderer;
28973
+ listComponent;
28423
28974
  get scrollbarWidth() {
28424
28975
  return this.supportService.scrollbarWidth;
28425
28976
  }
@@ -29104,12 +29655,12 @@ class GridComponent {
29104
29655
  this.sort = state.sort;
29105
29656
  this.group = state.group;
29106
29657
  this.filter = state.filter;
29107
- this.group = state.group;
29108
29658
  this.skip = state.skip;
29109
29659
  this.pageSize = state.take;
29110
- this.data = state.currentData;
29111
- this.changeNotification.notify();
29112
- this.changeDetectorRef.detectChanges();
29660
+ if (state.currentData) {
29661
+ this.data = state.currentData;
29662
+ }
29663
+ this.changeDetectorRef.markForCheck();
29113
29664
  }
29114
29665
  traverseColumns(columns, callback) {
29115
29666
  columns.forEach((column) => {
@@ -29320,6 +29871,9 @@ class GridComponent {
29320
29871
  source.locked = target.locked;
29321
29872
  }
29322
29873
  this.columnsContainer.refresh();
29874
+ if (this.virtualColumns) {
29875
+ this.listComponent.updateViewportColumns();
29876
+ }
29323
29877
  this.changeDetectorRef.markForCheck();
29324
29878
  });
29325
29879
  }
@@ -29742,7 +30296,8 @@ class GridComponent {
29742
30296
  column = toAdd.shift();
29743
30297
  viewportColumns.push(column);
29744
30298
  if (column.isColumnGroup) {
29745
- toAdd.unshift(...column.childrenArray);
30299
+ const children = columnsArray.filter(c => c.parent && c.parent.id === column.id);
30300
+ toAdd.unshift(...children);
29746
30301
  }
29747
30302
  }
29748
30303
  const lastFromGroup = viewportColumns[viewportColumns.length - 1];
@@ -29798,8 +30353,8 @@ class GridComponent {
29798
30353
  }
29799
30354
  if (this.groupsService.isExpanded({ groupIndex: index }) !== expand) {
29800
30355
  this.groupsService.toggleRow({ index }, false);
29801
- if (this.ctx.groupBindingDirective) {
29802
- this.ctx.groupBindingDirective[`group${expand ? 'Expand' : 'Collapse'}`]({ groupIndex: index });
30356
+ if (this.ctx.dataBindingDirective && this.ctx.dataBindingDirective instanceof GroupBindingDirective) {
30357
+ this.ctx.dataBindingDirective[`group${expand ? 'Expand' : 'Collapse'}`]({ groupIndex: index });
29803
30358
  }
29804
30359
  }
29805
30360
  }
@@ -29872,7 +30427,7 @@ class GridComponent {
29872
30427
  ColumnMenuService,
29873
30428
  MenuTabbingService,
29874
30429
  DataMappingService
29875
- ], queries: [{ propertyName: "columns", predicate: ColumnBase }, { propertyName: "detailTemplateChildren", predicate: DetailTemplateDirective }, { propertyName: "cellLoadingTemplateChildren", predicate: CellLoadingTemplateDirective }, { propertyName: "loadingTemplateChildren", predicate: LoadingTemplateDirective }, { propertyName: "statusBarTemplateChildren", predicate: StatusBarTemplateDirective }, { propertyName: "noRecordsTemplateChildren", predicate: NoRecordsTemplateDirective }, { propertyName: "pagerTemplateChildren", predicate: PagerTemplateDirective }, { propertyName: "toolbarTemplateChildren", predicate: ToolbarTemplateDirective }, { propertyName: "columnMenuTemplates", predicate: ColumnMenuTemplateDirective }], viewQueries: [{ propertyName: "lockedHeader", first: true, predicate: ["lockedHeader"], descendants: true }, { propertyName: "header", first: true, predicate: ["header"], descendants: true }, { propertyName: "ariaRoot", first: true, predicate: ["ariaRoot"], descendants: true, static: true }, { propertyName: "dragTargetContainer", first: true, predicate: DragTargetContainerDirective, descendants: true }, { propertyName: "dropTargetContainer", first: true, predicate: DropTargetContainerDirective, descendants: true }, { propertyName: "dialogContainer", first: true, predicate: ["dialogContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "adaptiveRenderer", first: true, predicate: AdaptiveRendererComponent, descendants: true }, { propertyName: "footer", predicate: ["footer"], descendants: true }], exportAs: ["kendoGrid"], usesOnChanges: true, ngImport: i0, template: `
30430
+ ], queries: [{ propertyName: "columns", predicate: ColumnBase }, { propertyName: "detailTemplateChildren", predicate: DetailTemplateDirective }, { propertyName: "cellLoadingTemplateChildren", predicate: CellLoadingTemplateDirective }, { propertyName: "loadingTemplateChildren", predicate: LoadingTemplateDirective }, { propertyName: "statusBarTemplateChildren", predicate: StatusBarTemplateDirective }, { propertyName: "noRecordsTemplateChildren", predicate: NoRecordsTemplateDirective }, { propertyName: "pagerTemplateChildren", predicate: PagerTemplateDirective }, { propertyName: "toolbarTemplateChildren", predicate: ToolbarTemplateDirective }, { propertyName: "columnMenuTemplates", predicate: ColumnMenuTemplateDirective }], viewQueries: [{ propertyName: "lockedHeader", first: true, predicate: ["lockedHeader"], descendants: true }, { propertyName: "header", first: true, predicate: ["header"], descendants: true }, { propertyName: "ariaRoot", first: true, predicate: ["ariaRoot"], descendants: true, static: true }, { propertyName: "dragTargetContainer", first: true, predicate: DragTargetContainerDirective, descendants: true }, { propertyName: "dropTargetContainer", first: true, predicate: DropTargetContainerDirective, descendants: true }, { propertyName: "dialogContainer", first: true, predicate: ["dialogContainer"], descendants: true, read: ViewContainerRef }, { propertyName: "adaptiveRenderer", first: true, predicate: AdaptiveRendererComponent, descendants: true }, { propertyName: "listComponent", first: true, predicate: ListComponent, descendants: true }, { propertyName: "footer", predicate: ["footer"], descendants: true }], exportAs: ["kendoGrid"], usesOnChanges: true, ngImport: i0, template: `
29876
30431
  <ng-container kendoGridLocalizedMessages
29877
30432
  i18n-groupPanelEmpty="kendo.grid.groupPanelEmpty|The label visible in the Grid group panel when it is empty"
29878
30433
  groupPanelEmpty="Drag a column header and drop it here to group by that column"
@@ -31689,6 +32244,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
31689
32244
  }], adaptiveRenderer: [{
31690
32245
  type: ViewChild,
31691
32246
  args: [AdaptiveRendererComponent]
32247
+ }], listComponent: [{
32248
+ type: ViewChild,
32249
+ args: [ListComponent]
31692
32250
  }] } });
31693
32251
 
31694
32252
  /**
@@ -31737,213 +32295,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
31737
32295
  }]
31738
32296
  }], ctorParameters: function () { return [{ type: i1$2.LocalizationService }]; } });
31739
32297
 
31740
- /**
31741
- * A directive that handles in-memory data operations like [paging]({% slug paging_grid %}),
31742
- * [sorting]({% slug sorting_grid %}), and [grouping]({% slug grouping_grid %}).
31743
- *
31744
- * Use this directive with local data and enable the Grid data operations with minimal configuration.
31745
- * ([More information and examples]({% slug local_data_grid %}#toc-using-the-data-binding-directive)).
31746
- *
31747
- * @example
31748
- * ```html
31749
- * <kendo-grid [kendoGridBinding]="gridData"></kendo-grid>
31750
- * ```
31751
- * @remarks
31752
- * Applied to: {@link GridComponent}.
31753
- */
31754
- class DataBindingDirective {
31755
- grid;
31756
- changeDetector;
31757
- localDataChangesService;
31758
- rowReorderService;
31759
- /**
31760
- * Sets the number of records to skip in the Grid.
31761
- *
31762
- * @default 0
31763
- */
31764
- set skip(value) {
31765
- if (!isPresent(value)) {
31766
- value = 0;
31767
- }
31768
- this.grid.skip = this.state.skip = value;
31769
- if (this.rowReorderService) {
31770
- this.rowReorderService.skip = value;
31771
- }
31772
- }
31773
- /**
31774
- * Sets the sort descriptors for the Grid data.
31775
- *
31776
- */
31777
- set sort(value) {
31778
- this.grid.sort = this.state.sort = value;
31779
- }
31780
- /**
31781
- * Sets the filter descriptor for the Grid data.
31782
- *
31783
- */
31784
- set filter(value) {
31785
- this.grid.filter = this.state.filter = value;
31786
- }
31787
- /**
31788
- * Sets the page size for the Grid pager.
31789
- *
31790
- */
31791
- set pageSize(value) {
31792
- this.grid.pageSize = this.state.take = value;
31793
- }
31794
- /**
31795
- * Sets the group descriptors for the Grid data.
31796
- *
31797
- */
31798
- set group(value) {
31799
- this.grid.group = this.state.group = value;
31800
- }
31801
- /**
31802
- * Sets the data array for the Grid.
31803
- *
31804
- */
31805
- set data(value) {
31806
- this.originalData = value || [];
31807
- if (this.localDataChangesService) {
31808
- this.localDataChangesService.data = value;
31809
- }
31810
- this.dataChanged = true;
31811
- }
31812
- state = {
31813
- skip: 0
31814
- };
31815
- originalData = [];
31816
- dataChanged;
31817
- stateChangeSubscription;
31818
- dataChangedSubscription;
31819
- rowReorderSubscription;
31820
- constructor(grid, changeDetector, localDataChangesService, rowReorderService) {
31821
- this.grid = grid;
31822
- this.changeDetector = changeDetector;
31823
- this.localDataChangesService = localDataChangesService;
31824
- this.rowReorderService = rowReorderService;
31825
- if (localDataChangesService) {
31826
- this.dataChangedSubscription = this.localDataChangesService.changes.subscribe(this.rebind.bind(this));
31827
- }
31828
- }
31829
- /**
31830
- * @hidden
31831
- */
31832
- ngOnInit() {
31833
- this.applyState(this.state);
31834
- this.stateChangeSubscription = this.grid
31835
- .dataStateChange
31836
- .subscribe(this.onStateChange.bind(this));
31837
- if (this.rowReorderService) {
31838
- this.rowReorderSubscription = this.grid
31839
- .rowReorder
31840
- .subscribe(this.onRowReorder.bind(this));
31841
- }
31842
- }
31843
- /**
31844
- * @hidden
31845
- */
31846
- ngOnDestroy() {
31847
- if (this.stateChangeSubscription) {
31848
- this.stateChangeSubscription.unsubscribe();
31849
- }
31850
- if (this.dataChangedSubscription) {
31851
- this.dataChangedSubscription.unsubscribe();
31852
- }
31853
- if (this.rowReorderSubscription) {
31854
- this.rowReorderSubscription.unsubscribe();
31855
- }
31856
- }
31857
- /**
31858
- * @hidden
31859
- */
31860
- ngOnChanges(changes) {
31861
- if (anyChanged(["pageSize", "skip", "sort", "group", "filter"], changes)) {
31862
- this.rebind();
31863
- }
31864
- }
31865
- ngDoCheck() {
31866
- if (this.dataChanged) {
31867
- this.updateGridData();
31868
- }
31869
- }
31870
- /**
31871
- * @hidden
31872
- */
31873
- onStateChange(state) {
31874
- this.applyState(state);
31875
- this.rebind();
31876
- }
31877
- /**
31878
- * @hidden
31879
- */
31880
- onRowReorder(ev) {
31881
- this.rowReorderService.reorderRows(ev, this.originalData);
31882
- this.rebind();
31883
- }
31884
- /**
31885
- * @hidden
31886
- */
31887
- rebind() {
31888
- this.data = this.originalData;
31889
- this.updateGridData();
31890
- this.notifyDataChange();
31891
- }
31892
- /**
31893
- * Notifies the Grid that its data has changed.
31894
- */
31895
- notifyDataChange() {
31896
- this.grid.onDataChange();
31897
- if (this.changeDetector) {
31898
- this.changeDetector.markForCheck();
31899
- }
31900
- }
31901
- process(state) {
31902
- if (this.grid.isVirtual && (!isPresent(state.take) || state.take === 0)) {
31903
- return {
31904
- data: [],
31905
- total: this.originalData?.length || 0
31906
- };
31907
- }
31908
- return process(this.originalData, state);
31909
- }
31910
- applyState({ skip, take, sort, group, filter }) {
31911
- this.skip = skip;
31912
- this.pageSize = take;
31913
- this.sort = sort;
31914
- this.group = group;
31915
- this.filter = filter;
31916
- }
31917
- updateGridData() {
31918
- this.grid.data = this.process(this.state);
31919
- this.grid.updateNavigationMetadata();
31920
- this.dataChanged = false;
31921
- }
31922
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DataBindingDirective, deps: [{ token: GridComponent }, { token: i0.ChangeDetectorRef }, { token: LocalDataChangesService }, { token: RowReorderService }], target: i0.ɵɵFactoryTarget.Directive });
31923
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: DataBindingDirective, isStandalone: true, selector: "[kendoGridBinding]", inputs: { skip: "skip", sort: "sort", filter: "filter", pageSize: "pageSize", group: "group", data: ["kendoGridBinding", "data"] }, exportAs: ["kendoGridBinding"], usesOnChanges: true, ngImport: i0 });
31924
- }
31925
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DataBindingDirective, decorators: [{
31926
- type: Directive,
31927
- args: [{
31928
- selector: '[kendoGridBinding]',
31929
- exportAs: 'kendoGridBinding',
31930
- standalone: true
31931
- }]
31932
- }], ctorParameters: function () { return [{ type: GridComponent }, { type: i0.ChangeDetectorRef }, { type: LocalDataChangesService }, { type: RowReorderService }]; }, propDecorators: { skip: [{
31933
- type: Input
31934
- }], sort: [{
31935
- type: Input
31936
- }], filter: [{
31937
- type: Input
31938
- }], pageSize: [{
31939
- type: Input
31940
- }], group: [{
31941
- type: Input
31942
- }], data: [{
31943
- type: Input,
31944
- args: ["kendoGridBinding"]
31945
- }] } });
31946
-
31947
32298
  /**
31948
32299
  * Stores the row selection state of the Grid in memory
31949
32300
  * ([see example]({% slug selection_grid %}#toc-toggling-the-selection-functionality)).
@@ -32846,330 +33197,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
32846
33197
  type: Input
32847
33198
  }] } });
32848
33199
 
32849
- const hasGroups = (items) => items && items.length && items[0].field && items[0].items;
32850
- const groupDescriptorsPresent = (descriptors) => isPresent(descriptors) && descriptors.length > 0;
32851
- const processGroups = (data, state) => process(data, state).data;
32852
- const removeParentDescriptors = (parents, owner) => g => g.field !== owner.field && !parents.some(y => y.field === g.field);
32853
- const findGroup = (groupIndex, groups) => {
32854
- const parents = [];
32855
- return {
32856
- group: groupIndex.split("_").reduce((acc, x) => {
32857
- const idx = parseInt(x, 10);
32858
- if (acc.items) {
32859
- parents.push(acc);
32860
- return acc.items[idx];
32861
- }
32862
- return isArray(acc) ? acc[idx] : acc;
32863
- }, groups),
32864
- parents
32865
- };
32866
- };
32867
- const findChildren = (data, parents) => {
32868
- const filters = parents.map(p => ({ field: p.field, operator: "eq", value: p.value }));
32869
- return filterBy(data, {
32870
- filters: filters,
32871
- logic: "and"
32872
- });
32873
- };
32874
- /**
32875
- * @hidden
32876
- */
32877
- const count = (groups, includeFooters = false) => (groups.reduce((acc, group) => {
32878
- if (!group.skipHeader) {
32879
- acc++;
32880
- }
32881
- if (group.items) {
32882
- const children = count(group.items, includeFooters);
32883
- if (includeFooters && children && !group.hideFooter) {
32884
- acc++;
32885
- }
32886
- acc += children;
32887
- }
32888
- return acc;
32889
- }, 0));
32890
- /**
32891
- * @hidden
32892
- */
32893
- const noDescriptors = (descriptors) => !isPresent(descriptors) || !descriptors.length;
32894
- /**
32895
- * @hidden
32896
- */
32897
- const slice = (groups, skip, take, includeFooters = false) => {
32898
- if (!isPresent(take)) {
32899
- return groups;
32900
- }
32901
- const result = [];
32902
- for (let idx = 0, length = groups.length; idx < length; idx++) {
32903
- if (take <= 0) {
32904
- break;
32905
- }
32906
- const group = groups[idx];
32907
- const groupItems = group.items;
32908
- let itemCount = count(groupItems, includeFooters);
32909
- if (includeFooters && groupItems.length) {
32910
- itemCount++;
32911
- }
32912
- const skipHeader = skip > 0;
32913
- if (skip) {
32914
- skip--;
32915
- if (itemCount && skip >= itemCount) {
32916
- skip -= itemCount;
32917
- continue;
32918
- }
32919
- }
32920
- if (!skipHeader || itemCount) {
32921
- const items = [];
32922
- let hideFooter = true;
32923
- if (!skipHeader) {
32924
- take--;
32925
- }
32926
- if (take) {
32927
- if (hasGroups(groupItems)) {
32928
- const children = slice(groupItems, skip, take, includeFooters);
32929
- items.push(...children);
32930
- take -= count(children, includeFooters);
32931
- }
32932
- else {
32933
- items.push(...groupItems.slice(skip, Math.min(skip + take, groupItems.length)));
32934
- take -= items.length;
32935
- }
32936
- if (take && includeFooters) {
32937
- hideFooter = false;
32938
- take--;
32939
- }
32940
- skip = 0;
32941
- }
32942
- result.push({
32943
- aggregates: group.aggregates,
32944
- field: group.field,
32945
- hideFooter,
32946
- items,
32947
- offset: idx,
32948
- skipHeader,
32949
- value: group.value
32950
- });
32951
- }
32952
- }
32953
- return result;
32954
- };
32955
- const skippedHeaders = (groupItem) => {
32956
- let total = 0;
32957
- while (groupItem) {
32958
- if (groupItem.skipHeader) {
32959
- total++;
32960
- }
32961
- groupItem = groupItem.items && groupItem.items[0] || null;
32962
- }
32963
- return total;
32964
- };
32965
- /**
32966
- * A directive which encapsulates the in-memory handling of grouping with virtual scrolling.
32967
- * @remarks
32968
- * Applied to: {@link GridComponent}.
32969
- */
32970
- class GroupBindingDirective extends DataBindingDirective {
32971
- groupsService;
32972
- /**
32973
- * The array of data which will be used to populate the Grid.
32974
- */
32975
- set kendoGridGroupBinding(value) {
32976
- this.groups = null;
32977
- this.grid.resetGroupsState();
32978
- this.data = value;
32979
- }
32980
- /**
32981
- * @hidden
32982
- */
32983
- set data(value) {
32984
- this.originalData = value || [];
32985
- this.dataChanged = true;
32986
- }
32987
- /**
32988
- * Defines the descriptors by which the data will be sorted.
32989
- */
32990
- set sort(value) {
32991
- const noCurrentDescriptors = noDescriptors(this.state.sort);
32992
- const noIncomingDescriptors = noDescriptors(value);
32993
- const clear = this.state.sort !== value && !(noCurrentDescriptors && noIncomingDescriptors);
32994
- this.grid.sort = this.state.sort = value;
32995
- if (clear) {
32996
- this.groups = null;
32997
- this.grid.resetGroupsState();
32998
- }
32999
- }
33000
- /**
33001
- * Defines the descriptor by which the data will be filtered.
33002
- */
33003
- set filter(value) {
33004
- const clear = diffFilters(this.state.filter, value);
33005
- if (clear) {
33006
- this.state.filter = value;
33007
- this.grid.filter = cloneFilters(value);
33008
- this.groups = null;
33009
- this.grid.resetGroupsState();
33010
- }
33011
- }
33012
- /**
33013
- * Defines the descriptors by which the data will be grouped.
33014
- */
33015
- set group(value) {
33016
- // don't clear if no groups are present in previous and current value
33017
- const groupsPresent = groupDescriptorsPresent(this.state.group) || groupDescriptorsPresent(value);
33018
- const clear = this.state.group !== value && groupsPresent;
33019
- this.grid.group = this.state.group = value;
33020
- if (clear) {
33021
- this.groups = null;
33022
- this.grid.resetGroupsState();
33023
- this.skip = 0;
33024
- }
33025
- }
33026
- groups;
33027
- gridSubs = new Subscription();
33028
- constructor(changeDetector, localDataChangesService, ctxService, groupsService) {
33029
- super(ctxService.grid, changeDetector, localDataChangesService);
33030
- this.groupsService = groupsService;
33031
- ctxService.groupBindingDirective = this;
33032
- }
33033
- ngOnInit() {
33034
- super.ngOnInit();
33035
- this.gridSubs.add(this.grid.groupExpand.subscribe(this.groupExpand.bind(this)));
33036
- this.gridSubs.add(this.grid.groupCollapse.subscribe(this.groupCollapse.bind(this)));
33037
- }
33038
- ngAfterContentInit() {
33039
- if (isDevMode() && this.grid.isGroupExpanded) {
33040
- throw new Error(GridConfigurationErrorMessages.groupBindingDirectives);
33041
- }
33042
- }
33043
- ngOnDestroy() {
33044
- this.gridSubs.unsubscribe();
33045
- }
33046
- /**
33047
- * @hidden
33048
- */
33049
- toggleAll(expand) {
33050
- this.skip = 0;
33051
- this.grid.scrollTo({ row: 0, column: 0 });
33052
- this.groups.forEach((gr, idx) => {
33053
- const expanded = this.groupsService.isExpanded({
33054
- group: gr,
33055
- groupIndex: idx.toString(),
33056
- parentGroup: undefined
33057
- });
33058
- const performToggle = (expand && !expanded) || (!expand && expanded);
33059
- if (performToggle) {
33060
- this.grid.groupsService.toggleRow({
33061
- type: 'group',
33062
- data: gr,
33063
- index: idx.toString(),
33064
- level: 0,
33065
- parentGroup: undefined
33066
- });
33067
- this[expand ? 'groupExpand' : 'groupCollapse']({ groupIndex: idx.toString() });
33068
- }
33069
- });
33070
- }
33071
- /**
33072
- * Collapses all expanded root level groups.
33073
- */
33074
- collapseAll() {
33075
- this.toggleAll(false);
33076
- }
33077
- /**
33078
- * Expands all expanded root level groups.
33079
- */
33080
- expandAll() {
33081
- this.toggleAll(true);
33082
- }
33083
- /**
33084
- * @hidden
33085
- */
33086
- groupExpand({ groupIndex }) {
33087
- const { group, parents } = findGroup(groupIndex, this.groups);
33088
- if (!group) {
33089
- return;
33090
- }
33091
- this.groupsService.expandChildren(groupIndex);
33092
- if (!group.items.length) {
33093
- const descriptors = this.state.group.filter(removeParentDescriptors(parents, group));
33094
- const children = findChildren(this.originalData, parents.concat(group));
33095
- group.items = processGroups(children, {
33096
- filter: this.state.filter,
33097
- group: descriptors,
33098
- sort: this.state.sort
33099
- });
33100
- }
33101
- this.grid.data = this.dataResult(this.state.skip, this.state.take);
33102
- }
33103
- /**
33104
- * @hidden
33105
- */
33106
- groupCollapse({ groupIndex }) {
33107
- const { group } = findGroup(groupIndex, this.groups);
33108
- if (group) {
33109
- group.items = [];
33110
- }
33111
- else {
33112
- return;
33113
- }
33114
- this.grid.data = this.dataResult(this.state.skip, this.state.take);
33115
- }
33116
- process(state) {
33117
- if (state.group && state.group.length) {
33118
- const groups = this.processGroups(state);
33119
- this.grid.skip -= skippedHeaders(groups.data[0]);
33120
- return groups;
33121
- }
33122
- else {
33123
- this.groups = null;
33124
- }
33125
- return super.process(state);
33126
- }
33127
- processGroups(state) {
33128
- if (!this.groups || !this.groups.length) {
33129
- this.groups = processGroups(this.originalData, {
33130
- filter: state.filter,
33131
- group: state.group,
33132
- sort: state.sort
33133
- });
33134
- }
33135
- return this.dataResult(state.skip, state.take);
33136
- }
33137
- dataResult(skip, take) {
33138
- const includeFooters = this.grid.showGroupFooters;
33139
- return {
33140
- data: slice(this.groups, skip, take, includeFooters),
33141
- total: count(this.groups, includeFooters)
33142
- };
33143
- }
33144
- applyState({ skip, take, sort, group, filter }) {
33145
- this.skip = skip;
33146
- this.state.take = take;
33147
- // this.pageSize = take; // do need to update take as the process with slice correctly
33148
- this.sort = sort;
33149
- this.group = group;
33150
- this.filter = filter;
33151
- }
33152
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: GroupBindingDirective, deps: [{ token: i0.ChangeDetectorRef }, { token: LocalDataChangesService }, { token: ContextService }, { token: GroupsService }], target: i0.ɵɵFactoryTarget.Directive });
33153
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: GroupBindingDirective, isStandalone: true, selector: "[kendoGridGroupBinding]", inputs: { kendoGridGroupBinding: "kendoGridGroupBinding", sort: "sort", filter: "filter", group: "group" }, exportAs: ["kendoGridGroupBinding"], usesInheritance: true, ngImport: i0 });
33154
- }
33155
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: GroupBindingDirective, decorators: [{
33156
- type: Directive,
33157
- args: [{
33158
- selector: '[kendoGridGroupBinding]',
33159
- exportAs: 'kendoGridGroupBinding',
33160
- standalone: true
33161
- }]
33162
- }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }, { type: LocalDataChangesService }, { type: ContextService }, { type: GroupsService }]; }, propDecorators: { kendoGridGroupBinding: [{
33163
- type: Input,
33164
- args: ["kendoGridGroupBinding"]
33165
- }], sort: [{
33166
- type: Input
33167
- }], filter: [{
33168
- type: Input
33169
- }], group: [{
33170
- type: Input
33171
- }] } });
33172
-
33173
33200
  /**
33174
33201
  * Represents the Kendo UI GridSpacer component for Angular.
33175
33202
  * Used to give additional white space between the Pager inner elements,
@@ -33822,6 +33849,12 @@ class UndoRedoStack {
33822
33849
  this.currentNode = this.currentNode.previous;
33823
33850
  return this.currentNode.state;
33824
33851
  }
33852
+ peekNext() {
33853
+ return this.currentNode.next?.state || null;
33854
+ }
33855
+ peekPrev() {
33856
+ return this.currentNode.previous?.state || null;
33857
+ }
33825
33858
  /**
33826
33859
  * Performs a redo operation, moving to the next state
33827
33860
  * @returns The next state or null if can't redo
@@ -33944,7 +33977,6 @@ class UndoRedoService {
33944
33977
  onUndo = new Subject();
33945
33978
  onRedo = new Subject();
33946
33979
  stackEndReached = new Subject();
33947
- setState = new Subject();
33948
33980
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UndoRedoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
33949
33981
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UndoRedoService });
33950
33982
  }
@@ -33968,11 +34000,17 @@ class UndoRedoDirective {
33968
34000
  editService;
33969
34001
  undoRedoService;
33970
34002
  changeNotification;
34003
+ ctx;
34004
+ localDataChangesService;
33971
34005
  /**
33972
34006
  * Sets the maximum number of actions to keep in the undo-redo stack.
33973
34007
  * @default 10
33974
34008
  */
33975
34009
  maxStoredStates = 10;
34010
+ /**
34011
+ * Defines the property name of the data item unique key that will be used to identify the items when performing undo-redo actions.
34012
+ */
34013
+ itemIdKey;
33976
34014
  /**
33977
34015
  * Fires when you perform the undo action. Provides the Grid state to apply.
33978
34016
  */
@@ -33990,11 +34028,13 @@ class UndoRedoDirective {
33990
34028
  stack;
33991
34029
  subs = new Subscription();
33992
34030
  addToState = true;
33993
- constructor(host, editService, undoRedoService, changeNotification) {
34031
+ constructor(host, editService, undoRedoService, changeNotification, ctx, localDataChangesService) {
33994
34032
  this.host = host;
33995
34033
  this.editService = editService;
33996
34034
  this.undoRedoService = undoRedoService;
33997
34035
  this.changeNotification = changeNotification;
34036
+ this.ctx = ctx;
34037
+ this.localDataChangesService = localDataChangesService;
33998
34038
  this.host.undoRedoService = this.undoRedoService;
33999
34039
  }
34000
34040
  ngOnInit() {
@@ -34006,7 +34046,7 @@ class UndoRedoDirective {
34006
34046
  sort: this.host.sort,
34007
34047
  filter: this.host.filter,
34008
34048
  group: this.host.group
34009
- }, gridState: structuredClone(this.host.currentState)
34049
+ }, gridState: this.host.currentState
34010
34050
  });
34011
34051
  this.subs = this.host.gridStateChange.subscribe((state) => {
34012
34052
  if (this.addToState) {
@@ -34018,7 +34058,7 @@ class UndoRedoDirective {
34018
34058
  filter: state.filter,
34019
34059
  group: state.group
34020
34060
  },
34021
- gridState: structuredClone(state)
34061
+ gridState: state
34022
34062
  });
34023
34063
  }
34024
34064
  let stackEndPointReached;
@@ -34031,36 +34071,72 @@ class UndoRedoDirective {
34031
34071
  this.undoRedoService.stackEndReached.next(stackEndPointReached);
34032
34072
  });
34033
34073
  this.subs.add(this.editService.changes
34034
- .pipe(filter(event => event.action === 'save' || event.action === 'remove'), tap(event => this.undoRedoService.originalEvent = event))
34074
+ .pipe(filter((event) => event.action === 'save' || event.action === 'remove'))
34035
34075
  .subscribe(event => {
34036
34076
  this.stack.add({
34037
- originalEvent: event,
34038
- gridState: structuredClone(this.host.currentState)
34077
+ originalEvent: { ...event, dataItem: structuredClone(event.dataItem) },
34078
+ gridState: this.host.currentState
34039
34079
  });
34040
34080
  this.addToState = false;
34041
34081
  this.host.gridStateChange.emit(this.stack.current.gridState);
34042
34082
  this.addToState = true;
34043
34083
  this.updateUndoRedoDisabled();
34044
34084
  }));
34045
- this.subs.add(this.changeNotification.changes.subscribe(() => this.stack.current.gridState = this.host.currentState));
34085
+ this.subs.add(this.changeNotification.changes.subscribe(() => {
34086
+ if (!this.ctx.dataBindingDirective) {
34087
+ this.stack.current.gridState = this.host.currentState;
34088
+ }
34089
+ }));
34046
34090
  ['Undo', 'Redo'].forEach((action) => {
34047
34091
  this.subs.add(this.undoRedoService[`on${action}`].subscribe(() => {
34048
34092
  if (!this.stack[`can${action}`]) {
34049
34093
  return;
34050
34094
  }
34051
- this.stack[`${action.toLowerCase()}`]();
34095
+ let eventData;
34096
+ if (action === 'Undo') {
34097
+ const isSaveOrRemove = this.stack.current.originalEvent.action === 'save' || this.stack.current.originalEvent.action === 'remove';
34098
+ eventData = isSaveOrRemove ? this.stack.current : this.stack.peekPrev();
34099
+ }
34100
+ else {
34101
+ eventData = this.stack.peekNext();
34102
+ }
34103
+ const event = new UndoRedoEvent(eventData);
34052
34104
  if (hasObservers(this[`on${action}`])) {
34053
- const event = new UndoRedoEvent(this.stack.current);
34054
34105
  this[`on${action}`].emit(event);
34055
34106
  if (event.isDefaultPrevented()) {
34056
34107
  return;
34057
34108
  }
34058
34109
  }
34110
+ this.stack[`${action.toLowerCase()}`]();
34059
34111
  this.updateUndoRedoDisabled();
34060
- this.host.loadState(this.stack.current.gridState);
34112
+ const originalAction = event.originalEvent.action;
34113
+ const isLocalData = isPresent$1(this.ctx?.dataBindingDirective);
34114
+ if (!isLocalData) {
34115
+ return;
34116
+ }
34117
+ const isSaveOrRemove = originalAction === 'save' || originalAction === 'remove';
34118
+ if (isSaveOrRemove) {
34119
+ if (originalAction === 'save') {
34120
+ const stateItem = this.getGridDataItems(this.stack.current.gridState.currentData).find(item => item[this.itemIdKey] === event.originalEvent.dataItem[this.itemIdKey]);
34121
+ Object.assign(event.originalEvent.originalDataItem, stateItem);
34122
+ }
34123
+ else if (action === 'Undo') {
34124
+ this.localDataChangesService?.data.splice(event.originalEvent.rowIndex, 0, event.originalEvent.dataItem);
34125
+ }
34126
+ else {
34127
+ this.localDataChangesService?.data.splice(event.originalEvent.rowIndex, 1);
34128
+ }
34129
+ this.localDataChangesService?.changes.emit();
34130
+ }
34131
+ else {
34132
+ this.host.loadState({ ...this.stack.current.gridState, currentData: null });
34133
+ if (this.isDataStateChangeEvent(event.originalEvent)) {
34134
+ const { skip, take, sort, filter, group } = this.stack.current.gridState;
34135
+ this.host.dataStateChange.emit({ skip, take, sort, filter, group });
34136
+ }
34137
+ }
34061
34138
  }));
34062
34139
  });
34063
- this.subs.add(this.undoRedoService.setState.subscribe((state) => this.stack.add({ originalEvent: 'dataChange', gridState: state })));
34064
34140
  }
34065
34141
  ngOnDestroy() {
34066
34142
  this.stack.clear();
@@ -34102,8 +34178,15 @@ class UndoRedoDirective {
34102
34178
  }
34103
34179
  this.undoRedoService.stackEndReached.next(false);
34104
34180
  }
34105
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UndoRedoDirective, deps: [{ token: GridComponent }, { token: EditService }, { token: UndoRedoService }, { token: ChangeNotificationService }], target: i0.ɵɵFactoryTarget.Directive });
34106
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: UndoRedoDirective, isStandalone: true, selector: "[kendoGridUndoRedo]", inputs: { maxStoredStates: "maxStoredStates" }, outputs: { onUndo: "undo", onRedo: "redo" }, providers: [UndoRedoService], exportAs: ["kendoGridUndoRedo"], ngImport: i0 });
34181
+ getGridDataItems(data) {
34182
+ return Array.isArray(data) ? data.flatMap(recursiveFlatMap) :
34183
+ data.data.flatMap(recursiveFlatMap);
34184
+ }
34185
+ isDataStateChangeEvent(event) {
34186
+ return event && ['skip', 'take', 'sort', 'filter', 'group'].some(prop => prop in event);
34187
+ }
34188
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UndoRedoDirective, deps: [{ token: GridComponent }, { token: EditService }, { token: UndoRedoService }, { token: ChangeNotificationService }, { token: ContextService }, { token: LocalDataChangesService }], target: i0.ɵɵFactoryTarget.Directive });
34189
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: UndoRedoDirective, isStandalone: true, selector: "[kendoGridUndoRedo]", inputs: { maxStoredStates: "maxStoredStates", itemIdKey: "itemIdKey" }, outputs: { onUndo: "undo", onRedo: "redo" }, providers: [UndoRedoService], exportAs: ["kendoGridUndoRedo"], ngImport: i0 });
34107
34190
  }
34108
34191
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UndoRedoDirective, decorators: [{
34109
34192
  type: Directive,
@@ -34113,7 +34196,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
34113
34196
  exportAs: 'kendoGridUndoRedo',
34114
34197
  providers: [UndoRedoService]
34115
34198
  }]
34116
- }], ctorParameters: function () { return [{ type: GridComponent }, { type: EditService }, { type: UndoRedoService }, { type: ChangeNotificationService }]; }, propDecorators: { maxStoredStates: [{
34199
+ }], ctorParameters: function () { return [{ type: GridComponent }, { type: EditService }, { type: UndoRedoService }, { type: ChangeNotificationService }, { type: ContextService }, { type: LocalDataChangesService }]; }, propDecorators: { maxStoredStates: [{
34200
+ type: Input
34201
+ }], itemIdKey: [{
34117
34202
  type: Input
34118
34203
  }], onUndo: [{
34119
34204
  type: Output,