@handsontable/angular-wrapper 17.0.1 → 17.1.0-rc10

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.
Files changed (30) hide show
  1. package/README.md +74 -0
  2. package/fesm2022/handsontable-angular-wrapper.mjs +100 -108
  3. package/fesm2022/handsontable-angular-wrapper.mjs.map +1 -1
  4. package/lib/editor/custom-editor-placeholder.component.d.ts +1 -1
  5. package/lib/editor/hot-cell-editor-advanced.component.d.ts +1 -1
  6. package/lib/editor/hot-cell-editor.component.d.ts +1 -1
  7. package/lib/hot-table.component.d.ts +10 -10
  8. package/lib/hot-table.module.d.ts +2 -6
  9. package/lib/renderer/hot-cell-renderer-advanced.component.d.ts +1 -1
  10. package/lib/renderer/hot-cell-renderer.component.d.ts +1 -1
  11. package/lib/services/hot-settings-resolver.service.d.ts +4 -5
  12. package/package.json +1 -1
  13. package/esm2022/handsontable-angular-wrapper.mjs +0 -5
  14. package/esm2022/lib/editor/base-editor-adapter.mjs +0 -180
  15. package/esm2022/lib/editor/custom-editor-placeholder.component.mjs +0 -89
  16. package/esm2022/lib/editor/editor-factory-adapter.mjs +0 -140
  17. package/esm2022/lib/editor/hot-cell-editor-advanced.component.mjs +0 -92
  18. package/esm2022/lib/editor/hot-cell-editor.component.mjs +0 -95
  19. package/esm2022/lib/editor/models/factory-editor-properties.mjs +0 -2
  20. package/esm2022/lib/editor/models/keyboard-shortcut-config.mjs +0 -2
  21. package/esm2022/lib/hot-table.component.mjs +0 -157
  22. package/esm2022/lib/hot-table.module.mjs +0 -29
  23. package/esm2022/lib/models/column-settings.mjs +0 -2
  24. package/esm2022/lib/models/grid-settings.mjs +0 -2
  25. package/esm2022/lib/renderer/hot-cell-renderer-advanced.component.mjs +0 -55
  26. package/esm2022/lib/renderer/hot-cell-renderer.component.mjs +0 -55
  27. package/esm2022/lib/renderer/hot-dynamic-renderer-component.service.mjs +0 -203
  28. package/esm2022/lib/services/hot-global-config.service.mjs +0 -107
  29. package/esm2022/lib/services/hot-settings-resolver.service.mjs +0 -170
  30. package/esm2022/public-api.mjs +0 -14
package/README.md CHANGED
@@ -55,6 +55,9 @@
55
55
  &nbsp;&nbsp;✅&nbsp; [Hiding columns](https://handsontable.com/docs/angular-data-grid/column-hiding/) <br>
56
56
  &nbsp;&nbsp;✅&nbsp; [Right-click context menu](https://handsontable.com/docs/angular-data-grid/context-menu/) <br>
57
57
  &nbsp;&nbsp;✅&nbsp; [Row pagination](https://handsontable.com/docs/angular-data-grid/rows-pagination/) <br>
58
+ &nbsp;&nbsp;✅&nbsp; [Server-side data](https://handsontable.com/docs/angular-data-grid/server-side-data/) <br>
59
+ &nbsp;&nbsp;✅&nbsp; [Notifications](https://handsontable.com/docs/angular-data-grid/notification/) <br>
60
+ &nbsp;&nbsp;✅&nbsp; [Export to Excel](https://handsontable.com/docs/angular-data-grid/export-to-excel/) <br>
58
61
 
59
62
  <div id="installation">
60
63
 
@@ -134,6 +137,77 @@ export class HotTableWrapperComponent {
134
137
 
135
138
  <br>
136
139
 
140
+ ## ⏳ Lazy loading with `@defer` (Angular 17+)
141
+
142
+ `HotTableComponent` is a standalone component and works with Angular's built-in
143
+ `@defer` block out of the box — no extra configuration required.
144
+
145
+ ### Recommended pattern
146
+
147
+ ```ts
148
+ import { Component, signal } from '@angular/core';
149
+ import { HotTableComponent } from '@handsontable/angular-wrapper';
150
+
151
+ @Component({
152
+ standalone: true,
153
+ imports: [HotTableComponent],
154
+ template: `
155
+ <button (click)="show.set(true)">Load grid</button>
156
+
157
+ @defer (when show()) {
158
+ <hot-table [data]="data" [settings]="settings"></hot-table>
159
+ } @placeholder {
160
+ <p>Click the button to load the grid.</p>
161
+ } @loading (minimum 300ms) {
162
+ <p>Loading…</p>
163
+ } @error {
164
+ <p>Failed to load the grid.</p>
165
+ }
166
+ `,
167
+ })
168
+ export class PageComponent {
169
+ show = signal(false);
170
+ data = [['Alice', 'has'], ['Bob', 'data']];
171
+ settings = { rowHeaders: true, colHeaders: ['Name', 'Note'] };
172
+ }
173
+ ```
174
+
175
+ ### How it works
176
+
177
+ | Block | When shown |
178
+ |---|---|
179
+ | `@defer (when show())` | renders `<hot-table>` after the signal becomes `true` |
180
+ | `@placeholder` | shown immediately before the trigger fires |
181
+ | `@loading (minimum 300ms)` | shown while the JS chunk is being fetched |
182
+ | `@error` | shown if the dynamic import fails |
183
+
184
+ ### Other trigger options
185
+
186
+ ```html
187
+ <!-- on viewport — loads when the placeholder scrolls into view -->
188
+ @defer (on viewport) { <hot-table …> }
189
+
190
+ <!-- on interaction — loads on first click/focus inside the placeholder -->
191
+ @defer (on interaction) { <hot-table …> }
192
+
193
+ <!-- on idle — loads during browser idle time -->
194
+ @defer (on idle) { <hot-table …> }
195
+ ```
196
+
197
+ ### Important: `registerAllModules()`
198
+
199
+ Call `registerAllModules()` in `app.config.ts` **before** the deferred block
200
+ triggers — it is synchronous and must run before any Handsontable instance is
201
+ created. The recommended place is at module level, outside any component:
202
+
203
+ ```ts
204
+ // app.config.ts
205
+ import { registerAllModules } from 'handsontable/registry';
206
+ registerAllModules(); // runs once at app startup, safe with @defer
207
+ ```
208
+
209
+ <br>
210
+
137
211
  ## 🎨 Themes
138
212
 
139
213
  Handsontable themes control how your data table looks: colors, spacing, typography, borders, and overall visual style.
@@ -1,7 +1,8 @@
1
1
  import * as i0 from '@angular/core';
2
- import { ViewContainerRef, Component, ChangeDetectionStrategy, Input, ViewChild, createComponent, EventEmitter, Directive, HostBinding, Output, Injectable, InjectionToken, Inject, ViewEncapsulation, NgModule } from '@angular/core';
2
+ import { ViewContainerRef, ViewChild, Input, ChangeDetectionStrategy, Component, createComponent, EventEmitter, Output, HostBinding, Directive, Injectable, InjectionToken, Inject, ViewEncapsulation, NgModule } from '@angular/core';
3
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
3
4
  import Handsontable from 'handsontable/base';
4
- import { take } from 'rxjs/operators';
5
+ import { take, skip } from 'rxjs/operators';
5
6
  import { editorFactory } from 'handsontable/editors/factory';
6
7
  import { baseRenderer, rendererFactory, registerRenderer } from 'handsontable/renderers';
7
8
  import { BehaviorSubject } from 'rxjs';
@@ -42,8 +43,8 @@ class CustomEditorPlaceholderComponent {
42
43
  detachEditor() {
43
44
  this.container.detach();
44
45
  }
45
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CustomEditorPlaceholderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
46
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: CustomEditorPlaceholderComponent, selector: "ng-component", inputs: { top: "top", left: "left", height: "height", width: "width", isVisible: "isVisible", placeholderCustomClass: "placeholderCustomClass", componentRef: "componentRef" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["inputPlaceholder"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: ` <div
46
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: CustomEditorPlaceholderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
47
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.21", type: CustomEditorPlaceholderComponent, isStandalone: true, selector: "ng-component", inputs: { top: "top", left: "left", height: "height", width: "width", isVisible: "isVisible", placeholderCustomClass: "placeholderCustomClass", componentRef: "componentRef" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["inputPlaceholder"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: ` <div
47
48
  [class]="placeholderCustomClass"
48
49
  [style.display]="display"
49
50
  [style.width.px]="width"
@@ -56,7 +57,7 @@ class CustomEditorPlaceholderComponent {
56
57
  <ng-template #inputPlaceholder></ng-template>
57
58
  </div>`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
58
59
  }
59
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: CustomEditorPlaceholderComponent, decorators: [{
60
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: CustomEditorPlaceholderComponent, decorators: [{
60
61
  type: Component,
61
62
  args: [{
62
63
  template: ` <div
@@ -72,7 +73,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
72
73
  <ng-template #inputPlaceholder></ng-template>
73
74
  </div>`,
74
75
  changeDetection: ChangeDetectionStrategy.OnPush,
75
- standalone: false,
76
+ standalone: true,
76
77
  }]
77
78
  }], propDecorators: { top: [{
78
79
  type: Input
@@ -297,14 +298,16 @@ class HotCellRendererComponent {
297
298
  getProps() {
298
299
  return this.cellProperties?.rendererProps ?? {};
299
300
  }
300
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotCellRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
301
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: HotCellRendererComponent, selector: "hot-cell-renderer", inputs: { value: "value", instance: "instance", td: "td", row: "row", col: "col", prop: "prop", cellProperties: "cellProperties" }, ngImport: i0, template: `<!-- This is an abstract component. Extend this component and provide your own template. -->`, isInline: true });
301
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotCellRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
302
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.21", type: HotCellRendererComponent, isStandalone: true, selector: "hot-cell-renderer", inputs: { value: "value", instance: "instance", td: "td", row: "row", col: "col", prop: "prop", cellProperties: "cellProperties" }, ngImport: i0, template: `<!-- This is an abstract component. Extend this component and provide your own template. -->`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
302
303
  }
303
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotCellRendererComponent, decorators: [{
304
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotCellRendererComponent, decorators: [{
304
305
  type: Component,
305
306
  args: [{
306
307
  selector: 'hot-cell-renderer',
307
- template: `<!-- This is an abstract component. Extend this component and provide your own template. -->`
308
+ template: `<!-- This is an abstract component. Extend this component and provide your own template. -->`,
309
+ standalone: true,
310
+ changeDetection: ChangeDetectionStrategy.OnPush,
308
311
  }]
309
312
  }], propDecorators: { value: [{
310
313
  type: Input
@@ -379,10 +382,10 @@ class HotCellEditorComponent {
379
382
  setValue(value) {
380
383
  this._value = value;
381
384
  }
382
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotCellEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
383
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: HotCellEditorComponent, inputs: { row: "row", column: "column", prop: "prop", originalValue: "originalValue", cellProperties: "cellProperties" }, outputs: { finishEdit: "finishEdit", cancelEdit: "cancelEdit" }, host: { properties: { "attr.tabindex": "this.tabindex", "attr.data-hot-input": "this.dataHotInput", "class.handsontableInput": "this.handsontableInputClass", "style.height.%": "this.heightFitParentContainer", "style.width.%": "this.widthFitParentContainer" } }, ngImport: i0 });
385
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotCellEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
386
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.21", type: HotCellEditorComponent, isStandalone: true, inputs: { row: "row", column: "column", prop: "prop", originalValue: "originalValue", cellProperties: "cellProperties" }, outputs: { finishEdit: "finishEdit", cancelEdit: "cancelEdit" }, host: { properties: { "attr.tabindex": "this.tabindex", "attr.data-hot-input": "this.dataHotInput", "class.handsontableInput": "this.handsontableInputClass", "style.height.%": "this.heightFitParentContainer", "style.width.%": "this.widthFitParentContainer" } }, ngImport: i0 });
384
387
  }
385
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotCellEditorComponent, decorators: [{
388
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotCellEditorComponent, decorators: [{
386
389
  type: Directive
387
390
  }], propDecorators: { tabindex: [{
388
391
  type: HostBinding,
@@ -514,8 +517,8 @@ function applyPropsToEditor(editor) {
514
517
  editor._componentRef.setInput('cellProperties', editor.cellProperties);
515
518
  const rect = editor.hot.getCell(editor.row, editor.col)?.getBoundingClientRect();
516
519
  editor._editorPlaceHolderRef.setInput('placeholderCustomClass', '');
517
- editor._editorPlaceHolderRef.setInput('height', rect.height);
518
- editor._editorPlaceHolderRef.setInput('width', rect.width);
520
+ editor._editorPlaceHolderRef.setInput('height', rect?.height ?? 0);
521
+ editor._editorPlaceHolderRef.setInput('width', rect?.width ?? 0);
519
522
  editor._editorPlaceHolderRef.setInput('isVisible', true);
520
523
  editor._editorPlaceHolderRef.setInput('componentRef', editor._componentRef);
521
524
  editor._editorPlaceHolderRef.changeDetectorRef.detectChanges();
@@ -579,14 +582,16 @@ class HotCellRendererAdvancedComponent {
579
582
  getProps() {
580
583
  return this.cellProperties?.rendererProps ?? {};
581
584
  }
582
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotCellRendererAdvancedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
583
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: HotCellRendererAdvancedComponent, selector: "hot-cell-renderer-advanced", inputs: { value: "value", instance: "instance", td: "td", row: "row", col: "col", prop: "prop", cellProperties: "cellProperties" }, ngImport: i0, template: `<!-- This is an abstract component. Extend this component and provide your own template. -->`, isInline: true });
585
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotCellRendererAdvancedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
586
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.21", type: HotCellRendererAdvancedComponent, isStandalone: true, selector: "hot-cell-renderer-advanced", inputs: { value: "value", instance: "instance", td: "td", row: "row", col: "col", prop: "prop", cellProperties: "cellProperties" }, ngImport: i0, template: `<!-- This is an abstract component. Extend this component and provide your own template. -->`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
584
587
  }
585
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotCellRendererAdvancedComponent, decorators: [{
588
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotCellRendererAdvancedComponent, decorators: [{
586
589
  type: Component,
587
590
  args: [{
588
591
  selector: 'hot-cell-renderer-advanced',
589
592
  template: `<!-- This is an abstract component. Extend this component and provide your own template. -->`,
593
+ standalone: true,
594
+ changeDetection: ChangeDetectionStrategy.OnPush,
590
595
  }]
591
596
  }], propDecorators: { value: [{
592
597
  type: Input
@@ -667,10 +672,10 @@ class HotCellEditorAdvancedComponent {
667
672
  afterInit(editor) { }
668
673
  /** Lifecycle hook called before the editor is opened. Available in advanced mode. */
669
674
  beforeOpen(editor, { row, col, prop, td, originalValue, cellProperties, }) { }
670
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotCellEditorAdvancedComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
671
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: HotCellEditorAdvancedComponent, inputs: { row: "row", column: "column", prop: "prop", originalValue: "originalValue", cellProperties: "cellProperties" }, outputs: { finishEdit: "finishEdit", cancelEdit: "cancelEdit" }, host: { properties: { "style.height.%": "this.heightFitParentContainer", "style.width.%": "this.widthFitParentContainer" } }, ngImport: i0 });
675
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotCellEditorAdvancedComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
676
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.21", type: HotCellEditorAdvancedComponent, isStandalone: true, inputs: { row: "row", column: "column", prop: "prop", originalValue: "originalValue", cellProperties: "cellProperties" }, outputs: { finishEdit: "finishEdit", cancelEdit: "cancelEdit" }, host: { properties: { "style.height.%": "this.heightFitParentContainer", "style.width.%": "this.widthFitParentContainer" } }, ngImport: i0 });
672
677
  }
673
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotCellEditorAdvancedComponent, decorators: [{
678
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotCellEditorAdvancedComponent, decorators: [{
674
679
  type: Directive
675
680
  }], propDecorators: { heightFitParentContainer: [{
676
681
  type: HostBinding,
@@ -851,7 +856,7 @@ class DynamicComponentService {
851
856
  environmentInjector: this.environmentInjector,
852
857
  });
853
858
  Object.keys(rendererParameters).forEach((key) => {
854
- if (rendererParameters.hasOwnProperty(key)) {
859
+ if (Object.prototype.hasOwnProperty.call(rendererParameters, key)) {
855
860
  componentRef.setInput(key, rendererParameters[key]);
856
861
  }
857
862
  else {
@@ -881,67 +886,56 @@ class DynamicComponentService {
881
886
  this.appRef.detachView(componentRef.hostView);
882
887
  componentRef.destroy();
883
888
  }
884
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicComponentService, deps: [{ token: i0.ApplicationRef }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable });
885
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicComponentService, providedIn: 'root' });
889
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: DynamicComponentService, deps: [{ token: i0.ApplicationRef }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable });
890
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: DynamicComponentService, providedIn: 'root' });
886
891
  }
887
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicComponentService, decorators: [{
892
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: DynamicComponentService, decorators: [{
888
893
  type: Injectable,
889
894
  args: [{
890
895
  providedIn: 'root',
891
896
  }]
892
- }], ctorParameters: function () { return [{ type: i0.ApplicationRef }, { type: i0.EnvironmentInjector }]; } });
897
+ }], ctorParameters: () => [{ type: i0.ApplicationRef }, { type: i0.EnvironmentInjector }] });
893
898
 
894
- const AVAILABLE_OPTIONS = Object.keys(Handsontable.DefaultSettings);
895
- const AVAILABLE_HOOKS = Handsontable.hooks.getRegistered();
899
+ const AVAILABLE_HOOKS_SET = new Set(Handsontable.hooks.getRegistered());
896
900
  /**
897
901
  * Service to resolve and apply custom settings for Handsontable settings object.
898
902
  */
899
903
  class HotSettingsResolver {
900
904
  dynamicComponentService;
901
905
  environmentInjector;
902
- constructor(dynamicComponentService, environmentInjector) {
906
+ ngZone;
907
+ constructor(dynamicComponentService, environmentInjector, ngZone) {
903
908
  this.dynamicComponentService = dynamicComponentService;
904
909
  this.environmentInjector = environmentInjector;
910
+ this.ngZone = ngZone;
905
911
  }
906
912
  /**
907
913
  * Applies custom settings to the provided GridSettings.
908
914
  * @param settings The original grid settings.
909
- * @param ngZone The NgZone instance to run hooks inside the zone context.
910
915
  * @returns The merged grid settings with custom settings applied.
911
916
  */
912
- applyCustomSettings(settings, ngZone) {
917
+ applyCustomSettings(settings) {
913
918
  const mergedSettings = settings;
914
919
  this.updateColumnRendererForGivenCustomRenderer(mergedSettings);
915
920
  this.updateColumnEditorForGivenCustomEditor(mergedSettings);
916
921
  this.updateColumnValidatorForGivenCustomValidator(mergedSettings);
917
- this.wrapHooksInNgZone(mergedSettings, ngZone);
922
+ this.wrapHooksInNgZone(mergedSettings);
918
923
  return mergedSettings ?? {};
919
924
  }
920
925
  /**
921
926
  * Ensures that hook callbacks in the provided grid settings run inside Angular's zone.
922
927
  *
923
928
  * @param settings The original grid settings.
924
- * @param ngZone The NgZone instance to run hooks inside the zone context.
925
929
  */
926
- wrapHooksInNgZone(settings, ngZone) {
927
- const options = AVAILABLE_HOOKS.concat(AVAILABLE_OPTIONS);
928
- options.forEach((key) => {
929
- const isHook = AVAILABLE_HOOKS.indexOf(key) > -1;
930
- let option;
931
- if (isHook) {
932
- option = settings[key];
933
- }
934
- if (option === void 0) {
935
- return;
936
- }
937
- else if (!!ngZone && typeof option === 'function' && isHook) {
930
+ wrapHooksInNgZone(settings) {
931
+ const ngZone = this.ngZone;
932
+ AVAILABLE_HOOKS_SET.forEach((key) => {
933
+ const option = settings[key];
934
+ if (typeof option === 'function') {
938
935
  settings[key] = function (...args) {
939
936
  return ngZone.run(() => option.apply(this, args));
940
937
  };
941
938
  }
942
- else {
943
- settings[key] = option;
944
- }
945
939
  });
946
940
  }
947
941
  /**
@@ -1044,12 +1038,12 @@ class HotSettingsResolver {
1044
1038
  this.isTemplateRef(renderer) ||
1045
1039
  this.isAdvancedRendererComponentRefType(renderer);
1046
1040
  }
1047
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotSettingsResolver, deps: [{ token: DynamicComponentService }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable });
1048
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotSettingsResolver });
1041
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotSettingsResolver, deps: [{ token: DynamicComponentService }, { token: i0.EnvironmentInjector }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable });
1042
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotSettingsResolver });
1049
1043
  }
1050
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotSettingsResolver, decorators: [{
1044
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotSettingsResolver, decorators: [{
1051
1045
  type: Injectable
1052
- }], ctorParameters: function () { return [{ type: DynamicComponentService }, { type: i0.EnvironmentInjector }]; } });
1046
+ }], ctorParameters: () => [{ type: DynamicComponentService }, { type: i0.EnvironmentInjector }, { type: i0.NgZone }] });
1053
1047
 
1054
1048
  /**
1055
1049
  * A constant representing the non-commercial and evaluation license.
@@ -1090,9 +1084,7 @@ class HotGlobalConfigService {
1090
1084
  * @private
1091
1085
  * @type {HotGlobalConfig}
1092
1086
  */
1093
- defaultConfig = {
1094
- license: undefined,
1095
- };
1087
+ defaultConfig = {};
1096
1088
  /**
1097
1089
  * A BehaviorSubject that holds the current Handsontable configuration.
1098
1090
  *
@@ -1142,54 +1134,50 @@ class HotGlobalConfigService {
1142
1134
  resetConfig() {
1143
1135
  this.configSubject.next({ ...this.defaultConfig });
1144
1136
  }
1145
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotGlobalConfigService, deps: [{ token: HOT_GLOBAL_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable });
1146
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotGlobalConfigService, providedIn: 'root' });
1137
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotGlobalConfigService, deps: [{ token: HOT_GLOBAL_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable });
1138
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotGlobalConfigService, providedIn: 'root' });
1147
1139
  }
1148
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotGlobalConfigService, decorators: [{
1140
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotGlobalConfigService, decorators: [{
1149
1141
  type: Injectable,
1150
1142
  args: [{
1151
1143
  providedIn: 'root',
1152
1144
  }]
1153
- }], ctorParameters: function () { return [{ type: undefined, decorators: [{
1145
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
1154
1146
  type: Inject,
1155
1147
  args: [HOT_GLOBAL_CONFIG]
1156
- }] }]; } });
1148
+ }] }] });
1157
1149
 
1158
- const HOT_DESTROYED_WARNING = 'The Handsontable instance bound to this component was destroyed and cannot be' + ' used properly.';
1150
+ const HOT_DESTROYED_WARNING = 'The Handsontable instance bound to this component was destroyed and cannot be used properly.';
1159
1151
  class HotTableComponent {
1160
1152
  _hotSettingsResolver;
1161
1153
  _hotConfig;
1162
1154
  ngZone;
1163
1155
  environmentInjector;
1164
- // component inputs
1156
+ destroyRef;
1165
1157
  /** The data for the Handsontable instance. */
1166
1158
  data = null;
1167
1159
  /** The settings for the Handsontable instance. */
1168
1160
  settings = {};
1169
- /** The container element for the Handsontable instance. */
1170
1161
  container;
1171
1162
  /** The Handsontable instance. */
1172
1163
  __hotInstance = null;
1173
- configSubscription;
1174
- constructor(_hotSettingsResolver, _hotConfig, ngZone, environmentInjector) {
1164
+ constructor(_hotSettingsResolver, _hotConfig, ngZone, environmentInjector, destroyRef) {
1175
1165
  this._hotSettingsResolver = _hotSettingsResolver;
1176
1166
  this._hotConfig = _hotConfig;
1177
1167
  this.ngZone = ngZone;
1178
1168
  this.environmentInjector = environmentInjector;
1169
+ this.destroyRef = destroyRef;
1179
1170
  }
1180
1171
  /**
1181
1172
  * Gets the Handsontable instance.
1182
1173
  * @returns The Handsontable instance or `null` if it's not yet been created or has been destroyed.
1183
1174
  */
1184
1175
  get hotInstance() {
1185
- if (!this.__hotInstance || (this.__hotInstance && !this.__hotInstance.isDestroyed)) {
1186
- // Will return the Handsontable instance or `null` if it's not yet been created.
1187
- return this.__hotInstance;
1188
- }
1189
- else {
1176
+ if (this.__hotInstance?.isDestroyed) {
1190
1177
  console.warn(HOT_DESTROYED_WARNING);
1191
1178
  return null;
1192
1179
  }
1180
+ return this.__hotInstance;
1193
1181
  }
1194
1182
  /**
1195
1183
  * Sets the Handsontable instance.
@@ -1203,7 +1191,7 @@ class HotTableComponent {
1203
1191
  * The initial settings of the table are also prepared here
1204
1192
  */
1205
1193
  ngAfterViewInit() {
1206
- let options = this._hotSettingsResolver.applyCustomSettings(this.settings, this.ngZone);
1194
+ let options = this._hotSettingsResolver.applyCustomSettings(this.settings);
1207
1195
  const negotiatedSettings = this.getNegotiatedSettings(options);
1208
1196
  options = { ...options, ...negotiatedSettings, data: this.data };
1209
1197
  this.ngZone.runOutsideAngular(() => {
@@ -1211,7 +1199,7 @@ class HotTableComponent {
1211
1199
  this.hotInstance._angularEnvironmentInjector = this.environmentInjector;
1212
1200
  this.hotInstance.init();
1213
1201
  });
1214
- this.configSubscription = this._hotConfig.config$.subscribe((config) => {
1202
+ this._hotConfig.config$.pipe(skip(1), takeUntilDestroyed(this.destroyRef)).subscribe(() => {
1215
1203
  if (this.hotInstance) {
1216
1204
  const negotiatedSettings = this.getNegotiatedSettings(this.settings);
1217
1205
  this.updateHotTable(negotiatedSettings);
@@ -1223,32 +1211,36 @@ class HotTableComponent {
1223
1211
  return;
1224
1212
  }
1225
1213
  if (changes.settings && !changes.settings.firstChange) {
1226
- const newOptions = this._hotSettingsResolver.applyCustomSettings(changes.settings.currentValue, this.ngZone);
1227
- this.updateHotTable(newOptions);
1214
+ this.destroyEditorComponentRefs();
1215
+ const newOptions = this._hotSettingsResolver.applyCustomSettings(changes.settings.currentValue);
1216
+ const dataChanged = changes.data && !changes.data.firstChange;
1217
+ this.updateHotTable(dataChanged ? { ...newOptions, data: changes.data.currentValue } : newOptions);
1218
+ return;
1228
1219
  }
1229
1220
  if (changes.data && !changes.data.firstChange) {
1230
- this.hotInstance?.updateData(changes.data.currentValue);
1221
+ this.ngZone.runOutsideAngular(() => {
1222
+ this.hotInstance.updateData(changes.data.currentValue);
1223
+ });
1231
1224
  }
1232
1225
  }
1233
1226
  /**
1234
1227
  * Destroys the Handsontable instance and clears the columns from custom editors.
1235
1228
  */
1236
1229
  ngOnDestroy() {
1230
+ if (!this.hotInstance) {
1231
+ return;
1232
+ }
1233
+ this.destroyEditorComponentRefs();
1237
1234
  this.ngZone.runOutsideAngular(() => {
1238
- if (!this.hotInstance) {
1239
- return;
1240
- }
1241
- const columns = this.hotInstance.getSettings().columns;
1242
- if (columns && Array.isArray(columns)) {
1243
- columns.forEach((column) => {
1244
- if (column._editorComponentReference) {
1245
- column._editorComponentReference.destroy();
1246
- }
1247
- });
1248
- }
1249
1235
  this.hotInstance.destroy();
1236
+ this.hotInstance = null;
1250
1237
  });
1251
- this.configSubscription.unsubscribe();
1238
+ }
1239
+ destroyEditorComponentRefs() {
1240
+ const columns = this.hotInstance.getSettings().columns;
1241
+ if (Array.isArray(columns)) {
1242
+ columns.forEach((column) => column._editorComponentReference?.destroy());
1243
+ }
1252
1244
  }
1253
1245
  /**
1254
1246
  * Updates the Handsontable instance with new settings.
@@ -1258,8 +1250,15 @@ class HotTableComponent {
1258
1250
  if (!this.hotInstance) {
1259
1251
  return;
1260
1252
  }
1253
+ const initOnlySettingKeys = new Set(this.hotInstance.getSettings()?._initOnlySettings ?? []);
1254
+ const filteredSettings = {};
1255
+ for (const key of Object.keys(newSettings)) {
1256
+ if (!initOnlySettingKeys.has(key)) {
1257
+ filteredSettings[key] = newSettings[key];
1258
+ }
1259
+ }
1261
1260
  this.ngZone.runOutsideAngular(() => {
1262
- this.hotInstance?.updateSettings(newSettings, false);
1261
+ this.hotInstance.updateSettings(filteredSettings, false);
1263
1262
  });
1264
1263
  }
1265
1264
  /**
@@ -1291,19 +1290,19 @@ class HotTableComponent {
1291
1290
  }
1292
1291
  return negotiatedSettings;
1293
1292
  }
1294
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotTableComponent, deps: [{ token: HotSettingsResolver }, { token: HotGlobalConfigService }, { token: i0.NgZone }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Component });
1295
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: HotTableComponent, selector: "hot-table", inputs: { data: "data", settings: "settings" }, providers: [HotSettingsResolver], viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], usesOnChanges: true, ngImport: i0, template: '<div #container></div>', isInline: true, styles: [":host{display:block}\n"], encapsulation: i0.ViewEncapsulation.None });
1293
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotTableComponent, deps: [{ token: HotSettingsResolver }, { token: HotGlobalConfigService }, { token: i0.NgZone }, { token: i0.EnvironmentInjector }, { token: i0.DestroyRef }], target: i0.ɵɵFactoryTarget.Component });
1294
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.21", type: HotTableComponent, isStandalone: true, selector: "hot-table", inputs: { data: "data", settings: "settings" }, providers: [HotSettingsResolver], viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], usesOnChanges: true, ngImport: i0, template: '<div #container></div>', isInline: true, styles: [":host{display:block}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1296
1295
  }
1297
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotTableComponent, decorators: [{
1296
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotTableComponent, decorators: [{
1298
1297
  type: Component,
1299
- args: [{ selector: 'hot-table', template: '<div #container></div>', encapsulation: ViewEncapsulation.None, providers: [HotSettingsResolver], styles: [":host{display:block}\n"] }]
1300
- }], ctorParameters: function () { return [{ type: HotSettingsResolver }, { type: HotGlobalConfigService }, { type: i0.NgZone }, { type: i0.EnvironmentInjector }]; }, propDecorators: { data: [{
1298
+ args: [{ selector: 'hot-table', template: '<div #container></div>', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [HotSettingsResolver], styles: [":host{display:block}\n"] }]
1299
+ }], ctorParameters: () => [{ type: HotSettingsResolver }, { type: HotGlobalConfigService }, { type: i0.NgZone }, { type: i0.EnvironmentInjector }, { type: i0.DestroyRef }], propDecorators: { data: [{
1301
1300
  type: Input
1302
1301
  }], settings: [{
1303
1302
  type: Input
1304
1303
  }], container: [{
1305
1304
  type: ViewChild,
1306
- args: ['container', { static: false }]
1305
+ args: ['container']
1307
1306
  }] } });
1308
1307
 
1309
1308
  class HotTableModule {
@@ -1311,25 +1310,18 @@ class HotTableModule {
1311
1310
  * Placeholder for the library version.
1312
1311
  * Replaced automatically during the pre-build/post-build process.
1313
1312
  */
1314
- static version = '17.0.1';
1315
- constructor() { }
1316
- static forRoot() {
1317
- return {
1318
- ngModule: HotTableModule,
1319
- };
1320
- }
1321
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotTableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1322
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: HotTableModule, declarations: [HotTableComponent, CustomEditorPlaceholderComponent], exports: [HotTableComponent] });
1323
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotTableModule });
1313
+ static version = '17.1.0-rc10';
1314
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotTableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1315
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.21", ngImport: i0, type: HotTableModule, imports: [HotTableComponent], exports: [HotTableComponent] });
1316
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotTableModule });
1324
1317
  }
1325
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HotTableModule, decorators: [{
1318
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: HotTableModule, decorators: [{
1326
1319
  type: NgModule,
1327
1320
  args: [{
1328
- declarations: [HotTableComponent, CustomEditorPlaceholderComponent],
1329
- imports: [],
1321
+ imports: [HotTableComponent],
1330
1322
  exports: [HotTableComponent],
1331
1323
  }]
1332
- }], ctorParameters: function () { return []; } });
1324
+ }] });
1333
1325
 
1334
1326
  /*
1335
1327
  * Public API Surface of hot-table