@handsontable/angular-wrapper 17.1.0-rc9 → 18.0.0-rc1

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.
@@ -0,0 +1,25 @@
1
+ import Handsontable from 'handsontable/base';
2
+ import { EventEmitter } from '@angular/core';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Shared base directive for HotCellEditorComponent and HotCellEditorAdvancedComponent.
6
+ * Holds all @Input(), @Output() and @HostBinding() declarations that both editor variants share.
7
+ *
8
+ * @template T - The type of the edited cell value.
9
+ */
10
+ export declare abstract class HotCellEditorBase<T extends string | number | boolean | Record<string, any> | Array<any>> {
11
+ protected heightFitParentContainer: number;
12
+ protected widthFitParentContainer: number;
13
+ row: number;
14
+ column: number;
15
+ prop: string | number;
16
+ originalValue: T;
17
+ cellProperties: Handsontable.CellProperties;
18
+ finishEdit: EventEmitter<void>;
19
+ cancelEdit: EventEmitter<void>;
20
+ protected value: T;
21
+ getValue(): T;
22
+ setValue(value: T): void;
23
+ static ɵfac: i0.ɵɵFactoryDeclaration<HotCellEditorBase<any>, never>;
24
+ static ɵdir: i0.ɵɵDirectiveDeclaration<HotCellEditorBase<any>, never, never, { "row": { "alias": "row"; "required": false; }; "column": { "alias": "column"; "required": false; }; "prop": { "alias": "prop"; "required": false; }; "originalValue": { "alias": "originalValue"; "required": false; }; "cellProperties": { "alias": "cellProperties"; "required": false; }; }, { "finishEdit": "finishEdit"; "cancelEdit": "cancelEdit"; }, never, never, true, never>;
25
+ }
@@ -1,10 +1,13 @@
1
- import { EventEmitter } from '@angular/core';
2
- import { CellProperties } from 'handsontable/settings';
1
+ import { HotCellEditorBase } from './hot-cell-editor-base.directive';
3
2
  import * as i0 from "@angular/core";
4
3
  /**
5
- * Abstract class representing a Handsontable editor in angular.
4
+ * Abstract class representing a basic Handsontable cell editor in Angular.
5
+ *
6
+ * Extend this class and decorate the subclass with `@Component()` to implement a custom editor.
7
+ * Value type is limited to primitives (`string | number | boolean`).
8
+ * For object and array values use {@link HotCellEditorAdvancedComponent}.
6
9
  */
7
- export declare abstract class HotCellEditorComponent<T extends string | number | boolean> {
10
+ export declare abstract class HotCellEditorComponent<T extends string | number | boolean> extends HotCellEditorBase<T> {
8
11
  static readonly EDITOR_MARKER: unique symbol;
9
12
  /** The tabindex attribute for the editor. */
10
13
  protected tabindex: number;
@@ -12,65 +15,23 @@ export declare abstract class HotCellEditorComponent<T extends string | number |
12
15
  protected dataHotInput: string;
13
16
  /** The handsontableInput class for the editor. */
14
17
  protected handsontableInputClass: boolean;
15
- /** The height of the editor as a percentage of the parent container. */
16
- protected heightFitParentContainer: number;
17
- /** The width of the editor as a percentage of the parent container. */
18
- protected widthFitParentContainer: number;
19
- /** The row index of the cell being edited. */
20
- row: number;
21
- /** The column index of the cell being edited. */
22
- column: number;
23
- /** The property name of the cell being edited. */
24
- prop: string | number;
25
- /** The original value of the cell being edited. */
26
- originalValue: T;
27
- /** The cell properties of the cell being edited. */
28
- cellProperties: CellProperties;
29
- /** Event emitted when the edit is finished.
30
- * The data will be saved to the model.
31
- */
32
- finishEdit: EventEmitter<void>;
33
- /** Event emitted when the edit is canceled.
34
- * The entered data will be reverted to the original value.
35
- */
36
- cancelEdit: EventEmitter<void>;
37
- /** The current value of the editor. */
38
- private _value;
39
- /** Event triggered by Handsontable on closing the editor.
40
- * The user can define their own actions for
41
- * the custom editor to be called after the base logic. */
18
+ /** Event triggered by Handsontable on closing the editor. */
42
19
  onClose(): void;
43
- /** Event triggered by Handsontable on open the editor.
44
- * The user can define their own actions for
45
- * the custom editor to be called after the base logic. */
20
+ /** Event triggered by Handsontable on opening the editor. */
46
21
  onOpen(event?: Event): void;
47
- /** Event triggered by Handsontable on focus the editor.
48
- * The user have to define focus logic.
22
+ /**
23
+ * Event triggered by Handsontable on focusing the editor.
24
+ * Must be implemented by the subclass to move focus to the actual input element.
49
25
  * @example
50
26
  * ```typescript
51
- * component({
52
- * template: `<input #inputElement>`
53
- * })
54
- * class CustomEditor extends HotEditor<string> {
27
+ * @Component({ template: `<input #inputElement>` })
28
+ * class CustomEditor extends HotCellEditorComponent<string> {
55
29
  * @ViewChild('inputElement') inputElement!: ElementRef;
56
- *
57
- * onFocus(): void {
58
- * this.inputElement.nativeElement.focus();
59
- * }
30
+ * onFocus(): void { this.inputElement.nativeElement.focus(); }
60
31
  * }
61
32
  * ```
62
33
  */
63
34
  abstract onFocus(): void;
64
- /**
65
- * Gets the current value of the editor.
66
- * @returns The current value of the editor.
67
- */
68
- getValue(): T;
69
- /**
70
- * Sets the current value of the editor.
71
- * @param value The value to set.
72
- */
73
- setValue(value: T): void;
74
35
  static ɵfac: i0.ɵɵFactoryDeclaration<HotCellEditorComponent<any>, never>;
75
- static ɵdir: i0.ɵɵDirectiveDeclaration<HotCellEditorComponent<any>, never, never, { "row": { "alias": "row"; "required": false; }; "column": { "alias": "column"; "required": false; }; "prop": { "alias": "prop"; "required": false; }; "originalValue": { "alias": "originalValue"; "required": false; }; "cellProperties": { "alias": "cellProperties"; "required": false; }; }, { "finishEdit": "finishEdit"; "cancelEdit": "cancelEdit"; }, never, never, true, never>;
36
+ static ɵdir: i0.ɵɵDirectiveDeclaration<HotCellEditorComponent<any>, never, never, {}, {}, never, never, true, never>;
76
37
  }
@@ -1,7 +1,15 @@
1
- import { ComponentRef } from '@angular/core';
1
+ import { ComponentRef, EnvironmentInjector } from '@angular/core';
2
2
  import { CustomEditorPlaceholderComponent } from '../custom-editor-placeholder.component';
3
3
  import { Subscription } from 'rxjs';
4
4
  import { HotCellEditorAdvancedComponent } from '../hot-cell-editor-advanced.component';
5
+ /**
6
+ * Handsontable core instance augmented with the Angular `EnvironmentInjector` that the wrapper
7
+ * stores on it (in `HotTableComponent`) so editor adapters can create components with the right
8
+ * injection context. Typed here to avoid scattered `as any` casts at the assignment/read sites.
9
+ */
10
+ export interface HotInstanceWithAngularInjector {
11
+ _angularEnvironmentInjector?: EnvironmentInjector;
12
+ }
5
13
  /**
6
14
  * Angular-specific properties that will be added to the editor instance.
7
15
  */
@@ -1,24 +1,27 @@
1
- import { AfterViewInit, DestroyRef, EnvironmentInjector, NgZone, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
1
+ import { AfterViewInit, ElementRef, EnvironmentInjector, NgZone, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
2
2
  import Handsontable from 'handsontable/base';
3
3
  import { HotSettingsResolver } from './services/hot-settings-resolver.service';
4
4
  import { HotGlobalConfigService } from './services/hot-global-config.service';
5
5
  import { GridSettings } from './models/grid-settings';
6
+ import { DynamicComponentService } from './renderer/hot-dynamic-renderer-component.service';
6
7
  import * as i0 from "@angular/core";
7
- export declare const HOT_DESTROYED_WARNING = "The Handsontable instance bound to this component was destroyed and cannot be used properly.";
8
+ export declare const HOT_DESTROYED_WARNING: string;
8
9
  export declare class HotTableComponent implements AfterViewInit, OnChanges, OnDestroy {
9
- private readonly _hotSettingsResolver;
10
- private readonly _hotConfig;
11
- private readonly ngZone;
10
+ private _hotSettingsResolver;
11
+ private _hotConfig;
12
+ ngZone: NgZone;
12
13
  private readonly environmentInjector;
13
- private readonly destroyRef;
14
+ private readonly _dynamicComponentService;
14
15
  /** The data for the Handsontable instance. */
15
16
  data: Handsontable.GridSettings['data'] | null;
16
17
  /** The settings for the Handsontable instance. */
17
18
  settings: GridSettings;
18
- private container;
19
+ /** The container element for the Handsontable instance. */
20
+ container: ElementRef<HTMLDivElement>;
19
21
  /** The Handsontable instance. */
20
22
  private __hotInstance;
21
- constructor(_hotSettingsResolver: HotSettingsResolver, _hotConfig: HotGlobalConfigService, ngZone: NgZone, environmentInjector: EnvironmentInjector, destroyRef: DestroyRef);
23
+ private readonly _destroyRef;
24
+ constructor(_hotSettingsResolver: HotSettingsResolver, _hotConfig: HotGlobalConfigService, ngZone: NgZone, environmentInjector: EnvironmentInjector, _dynamicComponentService: DynamicComponentService);
22
25
  /**
23
26
  * Gets the Handsontable instance.
24
27
  * @returns The Handsontable instance or `null` if it's not yet been created or has been destroyed.
@@ -39,7 +42,6 @@ export declare class HotTableComponent implements AfterViewInit, OnChanges, OnDe
39
42
  * Destroys the Handsontable instance and clears the columns from custom editors.
40
43
  */
41
44
  ngOnDestroy(): void;
42
- private destroyEditorComponentRefs;
43
45
  /**
44
46
  * Updates the Handsontable instance with new settings.
45
47
  * @param newSettings The new settings to apply to the Handsontable instance.
@@ -1,11 +1,7 @@
1
1
  import * as i0 from "@angular/core";
2
2
  import * as i1 from "./hot-table.component";
3
3
  export declare class HotTableModule {
4
- /**
5
- * Placeholder for the library version.
6
- * Replaced automatically during the pre-build/post-build process.
7
- */
8
- static readonly version = "17.1.0-rc9";
4
+ static readonly version = "18.0.0-rc1";
9
5
  static ɵfac: i0.ɵɵFactoryDeclaration<HotTableModule, never>;
10
6
  static ɵmod: i0.ɵɵNgModuleDeclaration<HotTableModule, never, [typeof i1.HotTableComponent], [typeof i1.HotTableComponent]>;
11
7
  static ɵinj: i0.ɵɵInjectorDeclaration<HotTableModule>;
@@ -6,6 +6,12 @@ import { HotCellRendererComponent } from '../renderer/hot-cell-renderer.componen
6
6
  import { HotCellEditorComponent } from '../editor/hot-cell-editor.component';
7
7
  import { HotCellRendererAdvancedComponent } from '../renderer/hot-cell-renderer-advanced.component';
8
8
  import { HotCellEditorAdvancedComponent } from '../editor/hot-cell-editor-advanced.component';
9
+ declare module 'handsontable/settings' {
10
+ interface ColumnSettings {
11
+ _editorComponentReference?: ComponentRef<HotCellEditorComponent<any>>;
12
+ _environmentInjector?: EnvironmentInjector;
13
+ }
14
+ }
9
15
  export type CustomValidatorFn<T> = (value: T) => boolean;
10
16
  export type ColumnSettings = Handsontable.ColumnSettings | {
11
17
  editor?: Type<HotCellEditorComponent<any>> | Type<HotCellEditorAdvancedComponent<any>> | Handsontable.ColumnSettings['editor'] | ExtendedEditor<any>;
@@ -1,33 +1,16 @@
1
- import Handsontable from 'handsontable/base';
1
+ import { HotCellRendererBase } from './hot-cell-renderer-base.directive';
2
2
  import * as i0 from "@angular/core";
3
3
  /**
4
4
  * Abstract base component for creating advanced custom cell renderer components for Handsontable.
5
5
  *
6
- * This class provides a common interface and properties required by any custom cell renderer.
6
+ * Extend this component and provide your own template to implement a custom renderer.
7
+ * Unlike {@link HotCellRendererComponent}, this variant also accepts object and array values.
7
8
  *
8
9
  * @template TValue - The type of the component renderer.
9
10
  * @template TProps - The type of additional renderer properties.
10
11
  */
11
- export declare abstract class HotCellRendererAdvancedComponent<TValue extends string | number | boolean | Record<string, any> | Array<any> = string, TProps extends {} = any> {
12
+ export declare abstract class HotCellRendererAdvancedComponent<TValue extends string | number | boolean | Record<string, any> | Array<any> = string, TProps extends {} = any> extends HotCellRendererBase<TValue, TProps> {
12
13
  static readonly RENDERER_MARKER: unique symbol;
13
- value: TValue;
14
- instance: Handsontable;
15
- td: HTMLTableCellElement;
16
- row: number;
17
- col: number;
18
- prop: string;
19
- /**
20
- * The cell properties provided by Handsontable, extended with optional renderer-specific properties.
21
- */
22
- cellProperties: Handsontable.CellProperties & {
23
- rendererProps?: TProps;
24
- };
25
- /**
26
- * Retrieves the renderer-specific properties from the cell properties.
27
- *
28
- * @returns The additional properties for the renderer.
29
- */
30
- getProps(): TProps;
31
14
  static ɵfac: i0.ɵɵFactoryDeclaration<HotCellRendererAdvancedComponent<any, any>, never>;
32
- static ɵcmp: i0.ɵɵComponentDeclaration<HotCellRendererAdvancedComponent<any, any>, "hot-cell-renderer-advanced", never, { "value": { "alias": "value"; "required": false; }; "instance": { "alias": "instance"; "required": false; }; "td": { "alias": "td"; "required": false; }; "row": { "alias": "row"; "required": false; }; "col": { "alias": "col"; "required": false; }; "prop": { "alias": "prop"; "required": false; }; "cellProperties": { "alias": "cellProperties"; "required": false; }; }, {}, never, never, true, never>;
15
+ static ɵcmp: i0.ɵɵComponentDeclaration<HotCellRendererAdvancedComponent<any, any>, "hot-cell-renderer-advanced", never, {}, {}, never, never, true, never>;
33
16
  }
@@ -0,0 +1,23 @@
1
+ import Handsontable from 'handsontable/base';
2
+ import * as i0 from "@angular/core";
3
+ /**
4
+ * Shared base directive for HotCellRendererComponent and HotCellRendererAdvancedComponent.
5
+ * Holds all @Input() properties and getProps() that both renderer variants share.
6
+ *
7
+ * @template TValue - The type of the rendered cell value.
8
+ * @template TProps - The type of additional renderer properties.
9
+ */
10
+ export declare abstract class HotCellRendererBase<TValue extends string | number | boolean | Record<string, any> | Array<any> = string, TProps extends {} = any> {
11
+ value: TValue;
12
+ instance: Handsontable;
13
+ td: HTMLTableCellElement;
14
+ row: number;
15
+ col: number;
16
+ prop: string | number;
17
+ cellProperties: Handsontable.CellProperties & {
18
+ rendererProps?: TProps;
19
+ };
20
+ getProps(): TProps;
21
+ static ɵfac: i0.ɵɵFactoryDeclaration<HotCellRendererBase<any, any>, never>;
22
+ static ɵdir: i0.ɵɵDirectiveDeclaration<HotCellRendererBase<any, any>, never, never, { "value": { "alias": "value"; "required": false; }; "instance": { "alias": "instance"; "required": false; }; "td": { "alias": "td"; "required": false; }; "row": { "alias": "row"; "required": false; }; "col": { "alias": "col"; "required": false; }; "prop": { "alias": "prop"; "required": false; }; "cellProperties": { "alias": "cellProperties"; "required": false; }; }, {}, never, never, true, never>;
23
+ }
@@ -1,33 +1,17 @@
1
- import Handsontable from 'handsontable/base';
1
+ import { HotCellRendererBase } from './hot-cell-renderer-base.directive';
2
2
  import * as i0 from "@angular/core";
3
3
  /**
4
4
  * Abstract base component for creating custom cell renderer components for Handsontable.
5
5
  *
6
- * This class provides a common interface and properties required by any custom cell renderer.
6
+ * Extend this component and provide your own template to implement a custom renderer.
7
+ * Value type is limited to primitives (`string | number | boolean`).
8
+ * For object and array values use {@link HotCellRendererAdvancedComponent}.
7
9
  *
8
10
  * @template TValue - The type of the component renderer.
9
11
  * @template TProps - The type of additional renderer properties.
10
12
  */
11
- export declare abstract class HotCellRendererComponent<TValue extends string | number | boolean = string, TProps extends {} = any> {
13
+ export declare abstract class HotCellRendererComponent<TValue extends string | number | boolean = string, TProps extends {} = any> extends HotCellRendererBase<TValue, TProps> {
12
14
  static readonly RENDERER_MARKER: unique symbol;
13
- value: TValue;
14
- instance: Handsontable;
15
- td: HTMLTableCellElement;
16
- row: number;
17
- col: number;
18
- prop: string;
19
- /**
20
- * The cell properties provided by Handsontable, extended with optional renderer-specific properties.
21
- */
22
- cellProperties: Handsontable.CellProperties & {
23
- rendererProps?: TProps;
24
- };
25
- /**
26
- * Retrieves the renderer-specific properties from the cell properties.
27
- *
28
- * @returns The additional properties for the renderer.
29
- */
30
- getProps(): TProps;
31
15
  static ɵfac: i0.ɵɵFactoryDeclaration<HotCellRendererComponent<any, any>, never>;
32
- static ɵcmp: i0.ɵɵComponentDeclaration<HotCellRendererComponent<any, any>, "hot-cell-renderer", never, { "value": { "alias": "value"; "required": false; }; "instance": { "alias": "instance"; "required": false; }; "td": { "alias": "td"; "required": false; }; "row": { "alias": "row"; "required": false; }; "col": { "alias": "col"; "required": false; }; "prop": { "alias": "prop"; "required": false; }; "cellProperties": { "alias": "cellProperties"; "required": false; }; }, {}, never, never, true, never>;
16
+ static ɵcmp: i0.ɵɵComponentDeclaration<HotCellRendererComponent<any, any>, "hot-cell-renderer", never, {}, {}, never, never, true, never>;
33
17
  }
@@ -39,6 +39,11 @@ export declare function isAdvancedHotCellRendererComponent(obj: any): obj is Typ
39
39
  export declare class DynamicComponentService {
40
40
  private appRef;
41
41
  private environmentInjector;
42
+ private readonly _tdComponentRefs;
43
+ private readonly _tdEmbeddedViews;
44
+ private readonly _instanceComponentRefs;
45
+ private readonly _instanceEmbeddedViews;
46
+ private readonly _hookedInstances;
42
47
  constructor(appRef: ApplicationRef, environmentInjector: EnvironmentInjector);
43
48
  /**
44
49
  * Creates a custom renderer function for Handsontable from an Angular component or TemplateRef.
@@ -59,13 +64,67 @@ export declare class DynamicComponentService {
59
64
  * @param register - If true, registers the renderer with Handsontable using the component's name.
60
65
  * @returns A renderer function that can be used in Handsontable's configuration.
61
66
  */
62
- createRendererWithFactory(component: Type<HotCellRendererAdvancedComponent>, componentProps?: Record<string, any>, register?: boolean): (instance: Handsontable.Core, td: HTMLTableCellElement, row: number, column: number, prop: string | number, value: any, cellProperties: Handsontable.CellProperties) => void;
67
+ createRendererWithFactory(component: Type<HotCellRendererAdvancedComponent>, componentProps?: Record<string, any>, register?: boolean): (instance: Handsontable, td: HTMLTableCellElement, row: number, column: number, prop: string | number, value: unknown, cellProperties: import("handsontable/settings").CellProperties) => void;
68
+ /**
69
+ * Destroys all renderer components and embedded views attached to cells within a container element.
70
+ * Must be called before destroying the Handsontable instance to prevent Angular component leaks.
71
+ *
72
+ * @param container - The root DOM element of the Handsontable instance.
73
+ * @param instance - The Handsontable instance whose registries should be torn down. When omitted
74
+ * (e.g. test stubs), only refs reachable through TDs still in the container are destroyed.
75
+ */
76
+ cleanupContainer(container: HTMLElement, instance?: Handsontable.Core): void;
77
+ /**
78
+ * Registers a one-time `afterViewRender` hook on the given Handsontable instance that sweeps
79
+ * renderer refs whose TD is no longer connected to the document. Handsontable recycles a pool of
80
+ * TD elements while virtualizing rows; cells that leave the viewport are never re-rendered, so
81
+ * without this sweep their Angular components stay attached to ApplicationRef and leak.
82
+ *
83
+ * Guarded against instances that do not expose `addHook` (e.g. test stubs).
84
+ *
85
+ * @param instance - The Handsontable instance whose render cycle drives the sweep.
86
+ */
87
+ private registerSweepHook;
88
+ /**
89
+ * Destroys every renderer ref/view tracked for the given instance whose root node is no longer
90
+ * attached to the document.
91
+ *
92
+ * @param instance - The Handsontable instance whose registries should be swept.
93
+ */
94
+ private sweepDetachedViews;
95
+ /**
96
+ * @returns True if any of the view's root nodes is still connected to the document.
97
+ */
98
+ private isViewConnected;
99
+ /**
100
+ * Destroys the renderer ref/view previously attached to a cell and clears the cell content,
101
+ * so a fresh renderer can take over the TD without leaking the old one.
102
+ *
103
+ * @param instance - The Handsontable instance owning the cell, used to update its registries.
104
+ * @param td - The table cell whose previous content should be torn down.
105
+ */
106
+ private replaceCellContent;
107
+ /**
108
+ * Tracks a component ref both by its TD (for fast replacement) and in the instance registry
109
+ * (for sweeping and full teardown).
110
+ */
111
+ private trackComponentRef;
112
+ /**
113
+ * Tracks an embedded view both by its TD (for fast replacement) and in the instance registry
114
+ * (for sweeping and full teardown).
115
+ */
116
+ private trackEmbeddedView;
117
+ /**
118
+ * Returns the per-instance registry set for the given instance, creating it on first use.
119
+ */
120
+ private registryFor;
63
121
  /**
64
122
  * Attaches an embedded view created from a TemplateRef to a given DOM element.
65
123
  *
66
124
  * @param template - The TemplateRef to create an embedded view from.
67
125
  * @param tdEl - The target DOM element (a table cell) to which the view will be appended.
68
126
  * @param properties - Context object providing properties to be used within the template.
127
+ * @returns The created EmbeddedViewRef so the caller can track and destroy it later.
69
128
  */
70
129
  private attachTemplateToElement;
71
130
  /**
@@ -76,6 +135,24 @@ export declare class DynamicComponentService {
76
135
  * @returns The ComponentRef of the dynamically created component.
77
136
  */
78
137
  private createComponent;
138
+ /**
139
+ * Renders an Angular component into the given cell, recycling the component already attached to
140
+ * the TD when it is of the same type. Handsontable recycles its pool of TD elements heavily while
141
+ * virtualizing rows, so recreating an Angular component on every re-render would cause needless
142
+ * teardown/instantiation churn and GC pressure. When the type matches we only refresh the inputs.
143
+ *
144
+ * @param td - The target table cell.
145
+ * @param component - The renderer component type to render.
146
+ * @param properties - The renderer parameters to feed as component inputs.
147
+ */
148
+ private renderComponent;
149
+ /**
150
+ * Assigns every renderer parameter as an input on the given component ref.
151
+ *
152
+ * @param componentRef - The component ref whose inputs should be set.
153
+ * @param rendererParameters - The renderer parameters to assign.
154
+ */
155
+ private applyInputs;
79
156
  /**
80
157
  * Attaches a dynamically created component's view to a specified DOM container element.
81
158
  *
@@ -86,9 +163,21 @@ export declare class DynamicComponentService {
86
163
  /**
87
164
  * Destroys a dynamically created component and detaches its view from the Angular application.
88
165
  *
166
+ * Idempotent: a TD recycled after `sweepDetachedViews` already destroyed its ref still maps to that
167
+ * stale ref in `_tdComponentRefs`, so the next render path may reach this with an already-destroyed
168
+ * ref. Guarding on `destroyed` skips the redundant detach/destroy instead of relying on Angular's
169
+ * internal no-op behaviour.
170
+ *
89
171
  * @param componentRef - The reference to the component to be destroyed.
90
172
  */
91
173
  destroyComponent<T>(componentRef: ComponentRef<T>): void;
174
+ /**
175
+ * Destroys an embedded view. Idempotent for the same reason as {@link destroyComponent}: a recycled
176
+ * TD can still map to an already-destroyed view in `_tdEmbeddedViews`.
177
+ *
178
+ * @param view - The embedded view to destroy.
179
+ */
180
+ private destroyEmbeddedView;
92
181
  static ɵfac: i0.ɵɵFactoryDeclaration<DynamicComponentService, never>;
93
182
  static ɵprov: i0.ɵɵInjectableDeclaration<DynamicComponentService>;
94
183
  }
@@ -1,6 +1,7 @@
1
1
  import { EnvironmentInjector, NgZone } from '@angular/core';
2
2
  import { DynamicComponentService } from '../renderer/hot-dynamic-renderer-component.service';
3
3
  import { GridSettings, GridSettingsInternal } from '../models/grid-settings';
4
+ import { ColumnSettings } from '../models/column-settings';
4
5
  import * as i0 from "@angular/core";
5
6
  /**
6
7
  * Service to resolve and apply custom settings for Handsontable settings object.
@@ -13,9 +14,12 @@ export declare class HotSettingsResolver {
13
14
  /**
14
15
  * Applies custom settings to the provided GridSettings.
15
16
  * @param settings The original grid settings.
17
+ * @param previousColumns The previously resolved columns (from the prior settings cycle). When
18
+ * supplied, an editor component already created for a column whose editor type is unchanged is
19
+ * recycled instead of being recreated, avoiding needless Angular component teardown/rebuild.
16
20
  * @returns The merged grid settings with custom settings applied.
17
21
  */
18
- applyCustomSettings(settings: GridSettings): GridSettingsInternal;
22
+ applyCustomSettings(settings: GridSettings, previousColumns?: ColumnSettings[]): GridSettingsInternal;
19
23
  /**
20
24
  * Ensures that hook callbacks in the provided grid settings run inside Angular's zone.
21
25
  *
@@ -29,9 +33,33 @@ export declare class HotSettingsResolver {
29
33
  private updateColumnRendererForGivenCustomRenderer;
30
34
  /**
31
35
  * Updates the column editor for columns with a custom editor.
36
+ *
37
+ * Iterates by original column index (not a filtered subset) so each column can be matched against
38
+ * the column at the same index in `previousColumns` for editor-component recycling.
39
+ *
32
40
  * @param mergedSettings The merged grid settings.
41
+ * @param previousColumns The previously resolved columns, used to recycle editor components.
33
42
  */
34
43
  private updateColumnEditorForGivenCustomEditor;
44
+ /**
45
+ * Returns the previous column's editor component ref when it can be reused for the new column, or
46
+ * `undefined` to signal a fresh component is needed.
47
+ *
48
+ * A ref is only recycled when, at the same index, both the editor component type AND the logical
49
+ * column identity (its `data` binding) are unchanged. The component-type check alone would already
50
+ * be functionally safe — a Handsontable editor is not per-cell rendered state but a single
51
+ * on-demand component that `BaseEditorAdapter`/`FactoryEditorAdapter` re-prepare on every edit
52
+ * (`prepare()` re-reads the ref from the *current* column meta and `applyPropsToEditor()` re-applies
53
+ * the full cell context on each `open()`). The extra `data` check is a defensive guard: when columns
54
+ * are reordered/shortened so a *different* logical column lands on an index, we build a fresh editor
55
+ * rather than carry the previous column's instance over, so no custom editor that caches
56
+ * column-specific config at construction can leak stale state into the new cell.
57
+ *
58
+ * @param previousColumn The column at the same index in the previous settings cycle.
59
+ * @param currentColumn The column now occupying this index.
60
+ * @param editorType The editor component type requested for the new column.
61
+ */
62
+ private reusableEditorRef;
35
63
  /**
36
64
  * Updates the column validator for columns with a custom validator.
37
65
  * @param mergedSettings The merged grid settings.
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@handsontable/angular-wrapper","version":"17.1.0-rc9","description":"Best Data Grid for Angular with Spreadsheet Look and Feel.","author":"Handsoncode <hello@handsoncode.net> (https://handsoncode.net)","license":"SEE LICENSE IN LICENSE.txt","homepage":"https://handsontable.com","keywords":["handsontable","component","data","table","grid","data table","data grid","spreadsheet","sheet","excel","angular","angular component","angular grid","wrapper","pro","enterprise","sort","formulas","filter","search","conditional formatting","csv"],"repository":{"type":"git","url":"https://github.com/handsontable/handsontable.git"},"bugs":{"url":"https://github.com/handsontable/handsontable/issues"},"peerDependencies":{"@angular/core":">=16.0.0 <22.0.0","handsontable":"^17.0.0","rxjs":"^7.0.0"},"publishConfig":{"directory":"dist/hot-table","linkDirectory":true},"module":"fesm2022/handsontable-angular-wrapper.mjs","typings":"index.d.ts","exports":{"./package.json":{"default":"./package.json"},".":{"types":"./index.d.ts","default":"./fesm2022/handsontable-angular-wrapper.mjs"}},"sideEffects":false,"optionalDependencies":{"tslib":"^2.3.0"}}
1
+ {"name":"@handsontable/angular-wrapper","version":"18.0.0-rc1","description":"Best Data Grid for Angular with Spreadsheet Look and Feel.","author":"Handsoncode <hello@handsoncode.net> (https://handsoncode.net)","license":"SEE LICENSE IN LICENSE.txt","homepage":"https://handsontable.com","keywords":["handsontable","component","data","table","grid","data table","data grid","spreadsheet","sheet","excel","angular","angular component","angular grid","wrapper","pro","enterprise","sort","formulas","filter","search","conditional formatting","csv"],"repository":{"type":"git","url":"https://github.com/handsontable/handsontable.git"},"bugs":{"url":"https://github.com/handsontable/handsontable/issues"},"peerDependencies":{"@angular/core":">=16.0.0 <23.0.0","handsontable":"^18.0.0","rxjs":"^7.0.0"},"publishConfig":{"directory":"dist/hot-table","linkDirectory":true},"module":"fesm2022/handsontable-angular-wrapper.mjs","typings":"index.d.ts","exports":{"./package.json":{"default":"./package.json"},".":{"types":"./index.d.ts","default":"./fesm2022/handsontable-angular-wrapper.mjs"}},"sideEffects":false,"optionalDependencies":{"tslib":"^2.3.0"}}