From f999d3d1d9edee2a2bd09f0217b6e189a4415b8a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:43:25 +0000 Subject: [PATCH 1/2] Initial plan From deec2b8e70b14ade2628ebf92e95a9209c08a51e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:57:52 +0000 Subject: [PATCH 2/2] Add null checks to prevent TypeError in IgxTextHighlightDirective lifecycle methods Co-authored-by: dkalinovInfra <130121354+dkalinovInfra@users.noreply.github.com> --- .../text-highlight.directive.spec.ts | 18 ++++++++++++++++++ .../text-highlight/text-highlight.directive.ts | 16 +++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.spec.ts b/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.spec.ts index faa0a923117..e7d4e83c4a6 100644 --- a/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.spec.ts +++ b/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.spec.ts @@ -308,6 +308,24 @@ describe('IgxHighlight', () => { expect(() => component.highlight.activateIfNecessary()).not.toThrowError(); }); + + it('Should not throw error when destroyed before ngAfterViewInit completes', () => { + const fix = TestBed.createComponent(HighlightLoremIpsumComponent); + // Do not call detectChanges() - this simulates destruction before ngAfterViewInit + + // Destroy the component before initialization completes + expect(() => fix.destroy()).not.toThrowError(); + }); + + it('Should return 0 when highlight is called before ngAfterViewInit completes', () => { + const fix = TestBed.createComponent(HighlightLoremIpsumComponent); + const component: HighlightLoremIpsumComponent = fix.debugElement.componentInstance; + + // Call highlight before detectChanges (before ngAfterViewInit) + const count = component.highlight.highlight('test', false, false); + + expect(count).toBe(0); + }); }); @Component({ diff --git a/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.ts b/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.ts index 5a7a1794f7e..5809d191100 100644 --- a/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.ts @@ -266,7 +266,7 @@ export class IgxTextHighlightDirective implements AfterViewInit, AfterViewChecke * @hidden */ public ngAfterViewChecked() { - if (this._valueChanged) { + if (this._valueChanged && this._lastSearchInfo) { this.highlight(this._lastSearchInfo.searchText, this._lastSearchInfo.caseSensitive, this._lastSearchInfo.exactMatch); this.activateIfNecessary(); this._valueChanged = false; @@ -278,6 +278,10 @@ export class IgxTextHighlightDirective implements AfterViewInit, AfterViewChecke * Returns how many times the element contains the searched text. */ public highlight(text: string, caseSensitive?: boolean, exactMatch?: boolean): number { + if (!this._lastSearchInfo) { + return 0; + } + const caseSensitiveResolved = caseSensitive ? true : false; const exactMatchResolved = exactMatch ? true : false; @@ -308,8 +312,10 @@ export class IgxTextHighlightDirective implements AfterViewInit, AfterViewChecke public clearHighlight(): void { this.clearChildElements(false); - this._lastSearchInfo.searchText = ''; - this._lastSearchInfo.matchCount = 0; + if (this._lastSearchInfo) { + this._lastSearchInfo.searchText = ''; + this._lastSearchInfo.matchCount = 0; + } } /** @@ -469,6 +475,10 @@ export class IgxTextHighlightDirective implements AfterViewInit, AfterViewChecke } private searchNeedsEvaluation(text: string, caseSensitive: boolean, exactMatch: boolean): boolean { + if (!this._lastSearchInfo) { + return false; + } + const searchedText = this._lastSearchInfo.searchText; return !this._nodeWasRemoved &&