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

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.
@@ -7,7 +7,6 @@ import { CellSelectionItem, SelectionEvent } from '../selection/types';
7
7
  import { RowArgs } from '../rendering/common/row-args';
8
8
  import { ContextService } from '../common/provider.service';
9
9
  import { ColumnInfoService } from '../common/column-info.service';
10
- import { LocalDataChangesService } from '../editing/local-data-changes.service';
11
10
  import * as i0 from "@angular/core";
12
11
  /**
13
12
  * @hidden
@@ -22,13 +21,12 @@ interface GroupedAggregates {
22
21
  */
23
22
  export declare class CellSelectionAggregateService {
24
23
  private ctx;
25
- private dataChanges;
26
24
  private columnInfoService;
27
25
  selectedItems: Array<CellSelectionItem | RowArgs>;
28
26
  groupedAggregates: GroupedAggregates;
29
27
  aggregates: SelectionAggregates;
30
28
  private sub;
31
- constructor(ctx: ContextService, dataChanges: LocalDataChangesService, columnInfoService: ColumnInfoService);
29
+ constructor(ctx: ContextService, columnInfoService: ColumnInfoService);
32
30
  ngOnDestroy(): void;
33
31
  isAggregateIncluded(aggregate: SelectionAggregate): boolean;
34
32
  init(): void;
@@ -6,7 +6,7 @@ import { ChangeDetectorRef, ElementRef, NgZone, Renderer2 } from '@angular/core'
6
6
  import { ContextService } from '../common/provider.service';
7
7
  import * as i0 from "@angular/core";
8
8
  /**
9
- * Represents a directive that manages keyboard navigation for a column menu item. [See example](slug:columnmenu_grid#customizing-the-content).
9
+ * Represents a directive that manages keyboard navigation for a column menu item ([see example](slug:columnmenu_grid#customizing-the-content)).
10
10
  *
11
11
  * @example
12
12
  * ```html
@@ -7,6 +7,7 @@ import { LocalizationService } from '@progress/kendo-angular-l10n';
7
7
  import type { GridComponent } from '../grid.component';
8
8
  import { GridToolbarNavigationService } from '../rendering/toolbar/toolbar-navigation.service';
9
9
  import type { GroupBindingDirective } from '../grouping/group-scroll-binding.directive';
10
+ import type { DataBindingDirective } from '../databinding.directive';
10
11
  import * as i0 from "@angular/core";
11
12
  /**
12
13
  * @hidden
@@ -24,7 +25,7 @@ export declare class ContextService {
24
25
  topToolbarNavigation: GridToolbarNavigationService;
25
26
  bottomToolbarNavigation: GridToolbarNavigationService;
26
27
  navigable: boolean;
27
- groupBindingDirective: GroupBindingDirective;
28
+ dataBindingDirective: DataBindingDirective | GroupBindingDirective;
28
29
  constructor(renderer: Renderer2, localization: LocalizationService);
29
30
  static ɵfac: i0.ɵɵFactoryDeclaration<ContextService, never>;
30
31
  static ɵprov: i0.ɵɵInjectableDeclaration<ContextService>;
@@ -10,6 +10,7 @@ import { GridDataResult } from './data/data.collection';
10
10
  import { LocalDataChangesService } from './editing/local-data-changes.service';
11
11
  import { RowReorderEvent } from './row-reordering/types';
12
12
  import { RowReorderService } from './row-reordering/row-reorder.service';
13
+ import { ContextService } from './common/provider.service';
13
14
  import * as i0 from "@angular/core";
14
15
  /**
15
16
  * A directive that handles in-memory data operations like [paging]({% slug paging_grid %}),
@@ -67,7 +68,7 @@ export declare class DataBindingDirective implements OnInit, OnDestroy, DoCheck,
67
68
  private stateChangeSubscription;
68
69
  private dataChangedSubscription;
69
70
  private rowReorderSubscription;
70
- constructor(grid: GridComponent, changeDetector?: ChangeDetectorRef, localDataChangesService?: LocalDataChangesService, rowReorderService?: RowReorderService);
71
+ constructor(grid: GridComponent, changeDetector?: ChangeDetectorRef, localDataChangesService?: LocalDataChangesService, rowReorderService?: RowReorderService, ctx?: ContextService);
71
72
  /**
72
73
  * @hidden
73
74
  */
@@ -5,19 +5,16 @@
5
5
  import { Injectable } from '@angular/core';
6
6
  import { ContextService } from '../common/provider.service';
7
7
  import { ColumnInfoService } from '../common/column-info.service';
8
- import { LocalDataChangesService } from '../editing/local-data-changes.service';
9
8
  import { recursiveFlatMap } from '../utils';
10
9
  import { Subscription } from 'rxjs';
11
10
  import * as i0 from "@angular/core";
12
11
  import * as i1 from "../common/provider.service";
13
- import * as i2 from "../editing/local-data-changes.service";
14
- import * as i3 from "../common/column-info.service";
12
+ import * as i2 from "../common/column-info.service";
15
13
  /**
16
14
  * @hidden
17
15
  */
18
16
  export class CellSelectionAggregateService {
19
17
  ctx;
20
- dataChanges;
21
18
  columnInfoService;
22
19
  selectedItems = [];
23
20
  groupedAggregates = { dates: [], numbers: [], booleans: [] };
@@ -33,9 +30,8 @@ export class CellSelectionAggregateService {
33
30
  latest: null
34
31
  };
35
32
  sub = new Subscription();
36
- constructor(ctx, dataChanges, columnInfoService) {
33
+ constructor(ctx, columnInfoService) {
37
34
  this.ctx = ctx;
38
- this.dataChanges = dataChanges;
39
35
  this.columnInfoService = columnInfoService;
40
36
  }
41
37
  ngOnDestroy() {
@@ -196,9 +192,9 @@ export class CellSelectionAggregateService {
196
192
  this.aggregates['isFalse'] = this.aggregates['isTrue'] = null;
197
193
  this.aggregates['earliest'] = this.aggregates['latest'] = null;
198
194
  }
199
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CellSelectionAggregateService, deps: [{ token: i1.ContextService }, { token: i2.LocalDataChangesService }, { token: i3.ColumnInfoService }], target: i0.ɵɵFactoryTarget.Injectable });
195
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CellSelectionAggregateService, deps: [{ token: i1.ContextService }, { token: i2.ColumnInfoService }], target: i0.ɵɵFactoryTarget.Injectable });
200
196
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CellSelectionAggregateService });
201
197
  }
202
198
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CellSelectionAggregateService, decorators: [{
203
199
  type: Injectable
204
- }], ctorParameters: function () { return [{ type: i1.ContextService }, { type: i2.LocalDataChangesService }, { type: i3.ColumnInfoService }]; } });
200
+ }], ctorParameters: function () { return [{ type: i1.ContextService }, { type: i2.ColumnInfoService }]; } });
@@ -12,7 +12,7 @@ import { ContextService } from '../common/provider.service';
12
12
  import * as i0 from "@angular/core";
13
13
  import * as i1 from "../common/provider.service";
14
14
  /**
15
- * Represents a directive that manages keyboard navigation for a column menu item. [See example](slug:columnmenu_grid#customizing-the-content).
15
+ * Represents a directive that manages keyboard navigation for a column menu item ([see example](slug:columnmenu_grid#customizing-the-content)).
16
16
  *
17
17
  * @example
18
18
  * ```html
@@ -23,7 +23,7 @@ export class ContextService {
23
23
  topToolbarNavigation;
24
24
  bottomToolbarNavigation;
25
25
  navigable;
26
- groupBindingDirective;
26
+ dataBindingDirective;
27
27
  constructor(renderer, localization) {
28
28
  this.renderer = renderer;
29
29
  this.localization = localization;
@@ -8,10 +8,12 @@ import { GridComponent } from './grid.component';
8
8
  import { anyChanged, isPresent } from './utils';
9
9
  import { LocalDataChangesService } from './editing/local-data-changes.service';
10
10
  import { RowReorderService } from './row-reordering/row-reorder.service';
11
+ import { ContextService } from './common/provider.service';
11
12
  import * as i0 from "@angular/core";
12
13
  import * as i1 from "./grid.component";
13
14
  import * as i2 from "./editing/local-data-changes.service";
14
15
  import * as i3 from "./row-reordering/row-reorder.service";
16
+ import * as i4 from "./common/provider.service";
15
17
  /**
16
18
  * A directive that handles in-memory data operations like [paging]({% slug paging_grid %}),
17
19
  * [sorting]({% slug sorting_grid %}), and [grouping]({% slug grouping_grid %}).
@@ -92,7 +94,7 @@ export class DataBindingDirective {
92
94
  stateChangeSubscription;
93
95
  dataChangedSubscription;
94
96
  rowReorderSubscription;
95
- constructor(grid, changeDetector, localDataChangesService, rowReorderService) {
97
+ constructor(grid, changeDetector, localDataChangesService, rowReorderService, ctx) {
96
98
  this.grid = grid;
97
99
  this.changeDetector = changeDetector;
98
100
  this.localDataChangesService = localDataChangesService;
@@ -100,6 +102,7 @@ export class DataBindingDirective {
100
102
  if (localDataChangesService) {
101
103
  this.dataChangedSubscription = this.localDataChangesService.changes.subscribe(this.rebind.bind(this));
102
104
  }
105
+ ctx && (ctx.dataBindingDirective = this);
103
106
  }
104
107
  /**
105
108
  * @hidden
@@ -194,7 +197,7 @@ export class DataBindingDirective {
194
197
  this.grid.updateNavigationMetadata();
195
198
  this.dataChanged = false;
196
199
  }
197
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DataBindingDirective, deps: [{ token: i1.GridComponent }, { token: i0.ChangeDetectorRef }, { token: i2.LocalDataChangesService }, { token: i3.RowReorderService }], target: i0.ɵɵFactoryTarget.Directive });
200
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DataBindingDirective, deps: [{ token: i1.GridComponent }, { token: i0.ChangeDetectorRef }, { token: i2.LocalDataChangesService }, { token: i3.RowReorderService }, { token: i4.ContextService }], target: i0.ɵɵFactoryTarget.Directive });
198
201
  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 });
199
202
  }
200
203
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DataBindingDirective, decorators: [{
@@ -204,7 +207,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
204
207
  exportAs: 'kendoGridBinding',
205
208
  standalone: true
206
209
  }]
207
- }], ctorParameters: function () { return [{ type: i1.GridComponent }, { type: i0.ChangeDetectorRef }, { type: i2.LocalDataChangesService }, { type: i3.RowReorderService }]; }, propDecorators: { skip: [{
210
+ }], ctorParameters: function () { return [{ type: i1.GridComponent }, { type: i0.ChangeDetectorRef }, { type: i2.LocalDataChangesService }, { type: i3.RowReorderService }, { type: i4.ContextService }]; }, propDecorators: { skip: [{
208
211
  type: Input
209
212
  }], sort: [{
210
213
  type: Input
@@ -100,6 +100,7 @@ import { AdaptiveGridService } from './common/adaptiveness.service';
100
100
  import { AdaptiveRendererComponent } from './adaptiveness/adaptive-renderer.component';
101
101
  import { ColumnMenuService } from './column-menu/column-menu.service';
102
102
  import { MenuTabbingService } from './filtering/menu/menu-tabbing.service';
103
+ import { GroupBindingDirective } from './grouping/group-scroll-binding.directive';
103
104
  import { DataMappingService } from './data/data-mapping.service';
104
105
  import * as i0 from "@angular/core";
105
106
  import * as i1 from "./layout/browser-support.service";
@@ -921,10 +922,8 @@ export class GridComponent {
921
922
  dragTargetContainer;
922
923
  dropTargetContainer;
923
924
  dialogContainer;
924
- /**
925
- * @hidden
926
- */
927
925
  adaptiveRenderer;
926
+ listComponent;
928
927
  get scrollbarWidth() {
929
928
  return this.supportService.scrollbarWidth;
930
929
  }
@@ -1609,12 +1608,12 @@ export class GridComponent {
1609
1608
  this.sort = state.sort;
1610
1609
  this.group = state.group;
1611
1610
  this.filter = state.filter;
1612
- this.group = state.group;
1613
1611
  this.skip = state.skip;
1614
1612
  this.pageSize = state.take;
1615
- this.data = state.currentData;
1616
- this.changeNotification.notify();
1617
- this.changeDetectorRef.detectChanges();
1613
+ if (state.currentData) {
1614
+ this.data = state.currentData;
1615
+ }
1616
+ this.changeDetectorRef.markForCheck();
1618
1617
  }
1619
1618
  traverseColumns(columns, callback) {
1620
1619
  columns.forEach((column) => {
@@ -1825,6 +1824,9 @@ export class GridComponent {
1825
1824
  source.locked = target.locked;
1826
1825
  }
1827
1826
  this.columnsContainer.refresh();
1827
+ if (this.virtualColumns) {
1828
+ this.listComponent.updateViewportColumns();
1829
+ }
1828
1830
  this.changeDetectorRef.markForCheck();
1829
1831
  });
1830
1832
  }
@@ -2247,7 +2249,8 @@ export class GridComponent {
2247
2249
  column = toAdd.shift();
2248
2250
  viewportColumns.push(column);
2249
2251
  if (column.isColumnGroup) {
2250
- toAdd.unshift(...column.childrenArray);
2252
+ const children = columnsArray.filter(c => c.parent && c.parent.id === column.id);
2253
+ toAdd.unshift(...children);
2251
2254
  }
2252
2255
  }
2253
2256
  const lastFromGroup = viewportColumns[viewportColumns.length - 1];
@@ -2303,8 +2306,8 @@ export class GridComponent {
2303
2306
  }
2304
2307
  if (this.groupsService.isExpanded({ groupIndex: index }) !== expand) {
2305
2308
  this.groupsService.toggleRow({ index }, false);
2306
- if (this.ctx.groupBindingDirective) {
2307
- this.ctx.groupBindingDirective[`group${expand ? 'Expand' : 'Collapse'}`]({ groupIndex: index });
2309
+ if (this.ctx.dataBindingDirective && this.ctx.dataBindingDirective instanceof GroupBindingDirective) {
2310
+ this.ctx.dataBindingDirective[`group${expand ? 'Expand' : 'Collapse'}`]({ groupIndex: index });
2308
2311
  }
2309
2312
  }
2310
2313
  }
@@ -2377,7 +2380,7 @@ export class GridComponent {
2377
2380
  ColumnMenuService,
2378
2381
  MenuTabbingService,
2379
2382
  DataMappingService
2380
- ], 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: `
2383
+ ], 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: `
2381
2384
  <ng-container kendoGridLocalizedMessages
2382
2385
  i18n-groupPanelEmpty="kendo.grid.groupPanelEmpty|The label visible in the Grid group panel when it is empty"
2383
2386
  groupPanelEmpty="Drag a column header and drop it here to group by that column"
@@ -4194,4 +4197,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
4194
4197
  }], adaptiveRenderer: [{
4195
4198
  type: ViewChild,
4196
4199
  args: [AdaptiveRendererComponent]
4200
+ }], listComponent: [{
4201
+ type: ViewChild,
4202
+ args: [ListComponent]
4197
4203
  }] } });
@@ -196,9 +196,9 @@ export class GroupBindingDirective extends DataBindingDirective {
196
196
  groups;
197
197
  gridSubs = new Subscription();
198
198
  constructor(changeDetector, localDataChangesService, ctxService, groupsService) {
199
- super(ctxService.grid, changeDetector, localDataChangesService);
199
+ super(ctxService.grid, changeDetector, localDataChangesService, null, ctxService);
200
200
  this.groupsService = groupsService;
201
- ctxService.groupBindingDirective = this;
201
+ ctxService.dataBindingDirective = this;
202
202
  }
203
203
  ngOnInit() {
204
204
  super.ngOnInit();
@@ -10,7 +10,7 @@ export const packageMetadata = {
10
10
  productName: 'Kendo UI for Angular',
11
11
  productCode: 'KENDOUIANGULAR',
12
12
  productCodes: ['KENDOUIANGULAR'],
13
- publishDate: 1750784754,
14
- version: '19.2.0-develop.1',
13
+ publishDate: 1751367404,
14
+ version: '19.2.0-develop.11',
15
15
  licensingDocsUrl: 'https://www.telerik.com/kendo-angular-ui/my-license/'
16
16
  };
@@ -270,7 +270,8 @@ export class ListComponent {
270
270
  if (this.virtualColumns && (!this.viewportColumns || this.viewportWidthChange())) {
271
271
  this.updateViewportColumns();
272
272
  }
273
- if (this.isVirtual && this.ctx.grid && !this.ctx.grid.pageSize) {
273
+ const shouldCalculatePageSize = isDocumentAvailable() && this.isVirtual && this.ctx.grid && !this.ctx.grid.pageSize;
274
+ if (shouldCalculatePageSize) {
274
275
  const calculatedPageSize = this.calcVirtualPageSize();
275
276
  if (calculatedPageSize > 0) {
276
277
  this.ngZone.onMicrotaskEmpty.pipe(take(1)).subscribe(() => {
@@ -352,6 +353,36 @@ export class ListComponent {
352
353
  args.preventDefault();
353
354
  }
354
355
  }
356
+ updateViewportColumns(range) {
357
+ const columns = this.columns.nonLockedLeafColumns.toArray();
358
+ // eslint-disable-next-line prefer-const
359
+ let { startIdx, endIdx, offset } = range || this.calculateViewportColumns();
360
+ const start = Math.max(0, startIdx - bufferSize);
361
+ const end = Math.min(endIdx + bufferSize, columns.length - 1);
362
+ if (start < startIdx) {
363
+ for (let idx = startIdx - 1; idx >= start; idx--) {
364
+ offset -= columns[idx].width;
365
+ }
366
+ }
367
+ let currentColumns = columns.slice(start, end + 1);
368
+ this.viewportColumnsWidth = currentColumns.reduce((total, column) => total + column.width, 0);
369
+ const stickyBeforeStart = columns.slice(0, start).filter(c => c.sticky && !currentColumns.some(col => col === c));
370
+ const stickyAfterEnd = columns.slice(end, columns.length).filter(c => c.sticky && !currentColumns.some(col => col === c));
371
+ currentColumns = [...stickyBeforeStart, ...currentColumns, ...stickyAfterEnd];
372
+ if (start > 0) {
373
+ const offsetColumn = new ColumnBase();
374
+ offsetColumn.width = offset;
375
+ currentColumns.unshift(offsetColumn);
376
+ }
377
+ this.viewportColumns = new QueryList();
378
+ this.viewportColumns.reset(currentColumns);
379
+ this.columnsStartIdx = start;
380
+ this.columnsEndIdx = end;
381
+ this.columnInfo.columnRangeChange.emit({ start, end, offset });
382
+ if (!range) {
383
+ this.updateColumnViewport(startIdx, endIdx);
384
+ }
385
+ }
355
386
  detailExpand({ index, expand }) {
356
387
  if (expand) {
357
388
  this.rowHeightService.expandDetail(index);
@@ -577,36 +608,6 @@ export class ListComponent {
577
608
  })
578
609
  .forEach(setHeight(this.renderer));
579
610
  }
580
- updateViewportColumns(range) {
581
- const columns = this.columns.nonLockedLeafColumns.toArray();
582
- // eslint-disable-next-line prefer-const
583
- let { startIdx, endIdx, offset } = range || this.calculateViewportColumns();
584
- const start = Math.max(0, startIdx - bufferSize);
585
- const end = Math.min(endIdx + bufferSize, columns.length - 1);
586
- if (start < startIdx) {
587
- for (let idx = startIdx - 1; idx >= start; idx--) {
588
- offset -= columns[idx].width;
589
- }
590
- }
591
- let currentColumns = columns.slice(start, end + 1);
592
- this.viewportColumnsWidth = currentColumns.reduce((total, column) => total + column.width, 0);
593
- const stickyBeforeStart = columns.slice(0, start).filter(c => c.sticky && !currentColumns.some(col => col === c));
594
- const stickyAfterEnd = columns.slice(end, columns.length).filter(c => c.sticky && !currentColumns.some(col => col === c));
595
- currentColumns = [...stickyBeforeStart, ...currentColumns, ...stickyAfterEnd];
596
- if (start > 0) {
597
- const offsetColumn = new ColumnBase();
598
- offsetColumn.width = offset;
599
- currentColumns.unshift(offsetColumn);
600
- }
601
- this.viewportColumns = new QueryList();
602
- this.viewportColumns.reset(currentColumns);
603
- this.columnsStartIdx = start;
604
- this.columnsEndIdx = end;
605
- this.columnInfo.columnRangeChange.emit({ start, end, offset });
606
- if (!range) {
607
- this.updateColumnViewport(startIdx, endIdx);
608
- }
609
- }
610
611
  handleColumnScroll() {
611
612
  const container = this.container.nativeElement;
612
613
  const scrollLeft = container.scrollLeft;
@@ -82,7 +82,7 @@ export class SelectionCheckboxDirective {
82
82
  const ctrlKey = event.ctrlKey || event.metaKey;
83
83
  if (event.shiftKey && this.selectionService.options.mode === 'multiple') {
84
84
  const item = { index: this.itemIndex };
85
- ev = this.selectionService.addAllTo(item, ctrlKey);
85
+ ev = this.selectionService.addAllTo(item, ctrlKey, false, event.shiftKey);
86
86
  }
87
87
  else {
88
88
  ev = this.selectionService.toggleByIndex(this.itemIndex);
@@ -143,6 +143,8 @@ export class SelectionService {
143
143
  if (ev.shiftKey) {
144
144
  ev.rangeStartRow = { dataItem: this.lastSelectionData, index: this.lastSelectionStartIndex };
145
145
  ev.rangeEndRow = { dataItem: item.data, index: item.index };
146
+ this.lastSelectionData = item.data;
147
+ this.lastSelectionStartIndex = item.index;
146
148
  }
147
149
  this.syncCurrentSelection(ev);
148
150
  this.changes.emit(ev);
@@ -231,13 +233,14 @@ export class SelectionService {
231
233
  item = iterator.next();
232
234
  }
233
235
  }
234
- addAllTo(item, ctrlKey, preserveSelection = false) {
236
+ addAllTo(item, ctrlKey, preserveSelection = false, shiftKey = false) {
235
237
  const selectedRows = [];
236
238
  const deselectedRows = [];
237
239
  const start = Math.min(this.lastSelectionStartIndex, item.index);
238
240
  const end = Math.max(this.lastSelectionStartIndex, item.index);
239
241
  const iterator = this.getIterator();
240
242
  let next = iterator.next();
243
+ let selectedItem;
241
244
  while (!next.done) {
242
245
  if (next.value && next.value.type === "data") {
243
246
  const idx = next.value.index;
@@ -248,6 +251,9 @@ export class SelectionService {
248
251
  if ((idx >= start && idx <= end) && !this.isSelected(idx) && !this.nonSelectableRows.has(idx)) {
249
252
  selectedRows.push(rowArgs);
250
253
  }
254
+ if (idx === item.index && !this.nonSelectableRows.has(idx)) {
255
+ selectedItem = rowArgs;
256
+ }
251
257
  }
252
258
  next = iterator.next();
253
259
  }
@@ -255,10 +261,23 @@ export class SelectionService {
255
261
  const nonSelectableRows = this.currentSelection.filter(i => this.nonSelectableRows.has(i.index));
256
262
  deselectedRows.push(...nonSelectableRows);
257
263
  }
258
- return {
259
- deselectedRows: deselectedRows,
260
- selectedRows: selectedRows
264
+ const selectionEvent = {
265
+ deselectedRows,
266
+ selectedRows
261
267
  };
268
+ if (shiftKey && selectedItem) {
269
+ selectionEvent.rangeStartRow = {
270
+ dataItem: this.lastSelectionData,
271
+ index: this.lastSelectionStartIndex
272
+ };
273
+ selectionEvent.rangeEndRow = {
274
+ dataItem: selectedItem.dataItem,
275
+ index: selectedItem.index
276
+ };
277
+ this.lastSelectionData = selectedItem.dataItem;
278
+ this.lastSelectionStartIndex = selectedItem.index;
279
+ }
280
+ return selectionEvent;
262
281
  }
263
282
  updateAll(selectAllChecked) {
264
283
  this.selectAllChecked = selectAllChecked;
@@ -8,15 +8,20 @@ import { GridComponent } from '../grid.component';
8
8
  import { UndoRedoEvent } from './grid-state.models';
9
9
  import { Subscription } from 'rxjs';
10
10
  import { EditService } from '../editing/edit.service';
11
- import { filter, tap } from 'rxjs/operators';
11
+ import { filter } from 'rxjs/operators';
12
12
  import { UndoRedoService } from './undo-redo.service';
13
- import { hasObservers } from '@progress/kendo-angular-common';
13
+ import { hasObservers, isPresent } from '@progress/kendo-angular-common';
14
14
  import { ChangeNotificationService } from '../data/change-notification.service';
15
+ import { ContextService } from '../common/provider.service';
16
+ import { LocalDataChangesService } from '../editing/local-data-changes.service';
17
+ import { recursiveFlatMap } from '../utils';
15
18
  import * as i0 from "@angular/core";
16
19
  import * as i1 from "../grid.component";
17
20
  import * as i2 from "../editing/edit.service";
18
21
  import * as i3 from "./undo-redo.service";
19
22
  import * as i4 from "../data/change-notification.service";
23
+ import * as i5 from "../common/provider.service";
24
+ import * as i6 from "../editing/local-data-changes.service";
20
25
  /**
21
26
  * Represents the directive that manages undo-redo operations in the Grid.
22
27
  * Use this directive to enable undo and redo functionality for user actions in the Grid.
@@ -33,11 +38,17 @@ export class UndoRedoDirective {
33
38
  editService;
34
39
  undoRedoService;
35
40
  changeNotification;
41
+ ctx;
42
+ localDataChangesService;
36
43
  /**
37
44
  * Sets the maximum number of actions to keep in the undo-redo stack.
38
45
  * @default 10
39
46
  */
40
47
  maxStoredStates = 10;
48
+ /**
49
+ * Defines the property name of the data item unique key that will be used to identify the items when performing undo-redo actions.
50
+ */
51
+ itemIdKey;
41
52
  /**
42
53
  * Fires when you perform the undo action. Provides the Grid state to apply.
43
54
  */
@@ -55,24 +66,17 @@ export class UndoRedoDirective {
55
66
  stack;
56
67
  subs = new Subscription();
57
68
  addToState = true;
58
- constructor(host, editService, undoRedoService, changeNotification) {
69
+ constructor(host, editService, undoRedoService, changeNotification, ctx, localDataChangesService) {
59
70
  this.host = host;
60
71
  this.editService = editService;
61
72
  this.undoRedoService = undoRedoService;
62
73
  this.changeNotification = changeNotification;
74
+ this.ctx = ctx;
75
+ this.localDataChangesService = localDataChangesService;
63
76
  this.host.undoRedoService = this.undoRedoService;
64
77
  }
65
78
  ngOnInit() {
66
79
  this.stack = new UndoRedoStack(this.maxStoredStates);
67
- this.stack.add({
68
- originalEvent: {
69
- skip: this.host.skip,
70
- take: this.host.pageSize,
71
- sort: this.host.sort,
72
- filter: this.host.filter,
73
- group: this.host.group
74
- }, gridState: structuredClone(this.host.currentState)
75
- });
76
80
  this.subs = this.host.gridStateChange.subscribe((state) => {
77
81
  if (this.addToState) {
78
82
  this.stack.add({
@@ -83,7 +87,7 @@ export class UndoRedoDirective {
83
87
  filter: state.filter,
84
88
  group: state.group
85
89
  },
86
- gridState: structuredClone(state)
90
+ gridState: state
87
91
  });
88
92
  }
89
93
  let stackEndPointReached;
@@ -96,36 +100,83 @@ export class UndoRedoDirective {
96
100
  this.undoRedoService.stackEndReached.next(stackEndPointReached);
97
101
  });
98
102
  this.subs.add(this.editService.changes
99
- .pipe(filter(event => event.action === 'save' || event.action === 'remove'), tap(event => this.undoRedoService.originalEvent = event))
103
+ .pipe(filter((event) => event.action === 'save' || event.action === 'remove'))
100
104
  .subscribe(event => {
101
105
  this.stack.add({
102
- originalEvent: event,
103
- gridState: structuredClone(this.host.currentState)
106
+ originalEvent: { ...event, dataItem: structuredClone(event.dataItem) },
107
+ gridState: this.host.currentState
104
108
  });
105
109
  this.addToState = false;
106
110
  this.host.gridStateChange.emit(this.stack.current.gridState);
107
111
  this.addToState = true;
108
112
  this.updateUndoRedoDisabled();
109
113
  }));
110
- this.subs.add(this.changeNotification.changes.subscribe(() => this.stack.current.gridState = this.host.currentState));
114
+ this.subs.add(this.changeNotification.changes.subscribe(() => {
115
+ if (!this.ctx.dataBindingDirective) {
116
+ this.stack.current.gridState = this.host.currentState;
117
+ }
118
+ }));
111
119
  ['Undo', 'Redo'].forEach((action) => {
112
120
  this.subs.add(this.undoRedoService[`on${action}`].subscribe(() => {
113
121
  if (!this.stack[`can${action}`]) {
114
122
  return;
115
123
  }
116
- this.stack[`${action.toLowerCase()}`]();
124
+ let eventData;
125
+ if (action === 'Undo') {
126
+ const isSaveOrRemove = this.stack.current.originalEvent.action === 'save' || this.stack.current.originalEvent.action === 'remove';
127
+ eventData = isSaveOrRemove ? this.stack.current : this.stack.peekPrev();
128
+ }
129
+ else {
130
+ eventData = this.stack.peekNext();
131
+ }
132
+ const event = new UndoRedoEvent(eventData);
117
133
  if (hasObservers(this[`on${action}`])) {
118
- const event = new UndoRedoEvent(this.stack.current);
119
134
  this[`on${action}`].emit(event);
120
135
  if (event.isDefaultPrevented()) {
121
136
  return;
122
137
  }
123
138
  }
139
+ this.stack[`${action.toLowerCase()}`]();
124
140
  this.updateUndoRedoDisabled();
125
- this.host.loadState(this.stack.current.gridState);
141
+ const originalAction = event.originalEvent.action;
142
+ const isLocalData = isPresent(this.ctx?.dataBindingDirective);
143
+ if (!isLocalData) {
144
+ return;
145
+ }
146
+ const isSaveOrRemove = originalAction === 'save' || originalAction === 'remove';
147
+ if (isSaveOrRemove) {
148
+ if (originalAction === 'save') {
149
+ const stateItem = this.getGridDataItems(this.stack.current.gridState.currentData).find(item => item[this.itemIdKey] === event.originalEvent.dataItem[this.itemIdKey]);
150
+ this.localDataChangesService?.data.splice(event.originalEvent.rowIndex, 1, stateItem);
151
+ }
152
+ else if (action === 'Undo') {
153
+ this.localDataChangesService?.data.splice(event.originalEvent.rowIndex, 0, event.originalEvent.dataItem);
154
+ }
155
+ else {
156
+ this.localDataChangesService?.data.splice(event.originalEvent.rowIndex, 1);
157
+ }
158
+ this.localDataChangesService?.changes.emit();
159
+ }
160
+ else {
161
+ this.host.loadState({ ...this.stack.current.gridState, currentData: null });
162
+ if (this.isDataStateChangeEvent(event.originalEvent)) {
163
+ const { skip, take, sort, filter, group } = event.gridState;
164
+ this.host.dataStateChange.emit({ skip, take, sort, filter, group });
165
+ }
166
+ }
126
167
  }));
127
168
  });
128
- this.subs.add(this.undoRedoService.setState.subscribe((state) => this.stack.add({ originalEvent: 'dataChange', gridState: state })));
169
+ }
170
+ ngAfterViewInit() {
171
+ this.stack.add({
172
+ originalEvent: {
173
+ skip: this.host.skip,
174
+ take: this.host.pageSize,
175
+ sort: this.host.sort,
176
+ filter: this.host.filter,
177
+ group: this.host.group
178
+ }, gridState: this.host.currentState
179
+ });
129
180
  }
130
181
  ngOnDestroy() {
131
182
  this.stack.clear();
@@ -167,8 +218,15 @@ export class UndoRedoDirective {
167
218
  }
168
219
  this.undoRedoService.stackEndReached.next(false);
169
220
  }
170
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UndoRedoDirective, deps: [{ token: i1.GridComponent }, { token: i2.EditService }, { token: i3.UndoRedoService }, { token: i4.ChangeNotificationService }], target: i0.ɵɵFactoryTarget.Directive });
171
- 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 });
221
+ getGridDataItems(data) {
222
+ return Array.isArray(data) ? data.flatMap(recursiveFlatMap) :
223
+ data.data.flatMap(recursiveFlatMap);
224
+ }
225
+ isDataStateChangeEvent(event) {
226
+ return event && ['skip', 'take', 'sort', 'filter', 'group'].some(prop => prop in event);
227
+ }
228
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UndoRedoDirective, deps: [{ token: i1.GridComponent }, { token: i2.EditService }, { token: i3.UndoRedoService }, { token: i4.ChangeNotificationService }, { token: i5.ContextService }, { token: i6.LocalDataChangesService }], target: i0.ɵɵFactoryTarget.Directive });
229
+ 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 });
172
230
  }
173
231
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UndoRedoDirective, decorators: [{
174
232
  type: Directive,
@@ -178,7 +236,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
178
236
  exportAs: 'kendoGridUndoRedo',
179
237
  providers: [UndoRedoService]
180
238
  }]
181
- }], ctorParameters: function () { return [{ type: i1.GridComponent }, { type: i2.EditService }, { type: i3.UndoRedoService }, { type: i4.ChangeNotificationService }]; }, propDecorators: { maxStoredStates: [{
239
+ }], ctorParameters: function () { return [{ type: i1.GridComponent }, { type: i2.EditService }, { type: i3.UndoRedoService }, { type: i4.ChangeNotificationService }, { type: i5.ContextService }, { type: i6.LocalDataChangesService }]; }, propDecorators: { maxStoredStates: [{
240
+ type: Input
241
+ }], itemIdKey: [{
182
242
  type: Input
183
243
  }], onUndo: [{
184
244
  type: Output,