From 4e08e9d11914711a83bca45750e6485060374606 Mon Sep 17 00:00:00 2001 From: Viktor Kombov Date: Tue, 21 Jul 2026 12:28:43 +0300 Subject: [PATCH 1/2] fix(month-picker): update keyboard navigation in zoneless apps --- .../src/calendar/calendar.services.ts | 8 +++-- .../month-picker.component.spec.ts | 29 ++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/projects/igniteui-angular/calendar/src/calendar/calendar.services.ts b/projects/igniteui-angular/calendar/src/calendar/calendar.services.ts index 1873e35cc63..c317ab37c7d 100644 --- a/projects/igniteui-angular/calendar/src/calendar/calendar.services.ts +++ b/projects/igniteui-angular/calendar/src/calendar/calendar.services.ts @@ -1,4 +1,4 @@ -import { Injectable, ElementRef, NgZone, inject } from "@angular/core"; +import { ChangeDetectorRef, ElementRef, Injectable, NgZone, inject } from "@angular/core"; import { EventManager } from "@angular/platform-browser"; import { PlatformUtil } from 'igniteui-angular/core'; @@ -6,6 +6,7 @@ import { PlatformUtil } from 'igniteui-angular/core'; export class KeyboardNavigationService { private eventManager = inject(EventManager); private ngZone = inject(NgZone); + private cdr = inject(ChangeDetectorRef); private keyHandlers = new Map void>(); private eventUnsubscribeFn: Function | null = null; @@ -26,7 +27,10 @@ export class KeyboardNavigationService { const handler = this.keyHandlers.get(event.key); if (handler) { - this.ngZone.run(handler.bind(context, event)); + this.ngZone.run(() => { + handler.call(context, event); + this.cdr.markForCheck(); + }); } } ); diff --git a/projects/igniteui-angular/calendar/src/calendar/month-picker/month-picker.component.spec.ts b/projects/igniteui-angular/calendar/src/calendar/month-picker/month-picker.component.spec.ts index 6ade99fc1d1..1d62a9258c5 100644 --- a/projects/igniteui-angular/calendar/src/calendar/month-picker/month-picker.component.spec.ts +++ b/projects/igniteui-angular/calendar/src/calendar/month-picker/month-picker.component.spec.ts @@ -1,4 +1,4 @@ -import { Component, ViewChild, ChangeDetectionStrategy } from '@angular/core'; +import { ChangeDetectionStrategy, Component, provideZonelessChangeDetection, ViewChild } from '@angular/core'; import { TestBed } from '@angular/core/testing'; import { FormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; @@ -729,6 +729,33 @@ describe('IgxMonthPicker', () => { expect(monthPicker.activeView).toBe(IgxCalendarView.Decade); }); + + describe('in zoneless change detection', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [provideZonelessChangeDetection()] + }); + }); + + it('should update the highlighted month after keyboard navigation', async () => { + const fixture = TestBed.createComponent(IgxMonthPickerSampleComponent); + fixture.detectChanges(); + await fixture.whenStable(); + + const monthPicker = fixture.componentInstance.monthPicker; + const wrapper = fixture.debugElement.query(By.css('.igx-calendar__wrapper')); + wrapper.nativeElement.focus(); + await fixture.whenStable(); + const initiallyHighlightedMonth = fixture.debugElement.query(By.css('.igx-calendar-view__item--selected')); + UIInteractions.triggerKeyDownEvtUponElem('ArrowRight', wrapper.nativeElement); + await fixture.whenStable(); + + expect(monthPicker.monthsView.date.getMonth()).toBe(2); + const highlightedMonth = fixture.debugElement.query(By.css('.igx-calendar-view__item--selected')); + expect(highlightedMonth.nativeElement).not.toBe(initiallyHighlightedMonth.nativeElement); + expect(highlightedMonth.nativeElement.textContent.trim()).toBe('Mar'); + }); + }); }); @Component({ From e87c11da8d47d11fd2b89bd1a6b5ad7fb1f6f8e3 Mon Sep 17 00:00:00 2001 From: Viktor Kombov Date: Tue, 21 Jul 2026 13:17:09 +0300 Subject: [PATCH 2/2] fix(month-picker): improve structure and quality of zoneless test --- .../month-picker.component.spec.ts | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/projects/igniteui-angular/calendar/src/calendar/month-picker/month-picker.component.spec.ts b/projects/igniteui-angular/calendar/src/calendar/month-picker/month-picker.component.spec.ts index 1d62a9258c5..eb4e6b320ef 100644 --- a/projects/igniteui-angular/calendar/src/calendar/month-picker/month-picker.component.spec.ts +++ b/projects/igniteui-angular/calendar/src/calendar/month-picker/month-picker.component.spec.ts @@ -730,32 +730,6 @@ describe('IgxMonthPicker', () => { expect(monthPicker.activeView).toBe(IgxCalendarView.Decade); }); - describe('in zoneless change detection', () => { - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideZonelessChangeDetection()] - }); - }); - - it('should update the highlighted month after keyboard navigation', async () => { - const fixture = TestBed.createComponent(IgxMonthPickerSampleComponent); - fixture.detectChanges(); - await fixture.whenStable(); - - const monthPicker = fixture.componentInstance.monthPicker; - const wrapper = fixture.debugElement.query(By.css('.igx-calendar__wrapper')); - wrapper.nativeElement.focus(); - await fixture.whenStable(); - const initiallyHighlightedMonth = fixture.debugElement.query(By.css('.igx-calendar-view__item--selected')); - UIInteractions.triggerKeyDownEvtUponElem('ArrowRight', wrapper.nativeElement); - await fixture.whenStable(); - - expect(monthPicker.monthsView.date.getMonth()).toBe(2); - const highlightedMonth = fixture.debugElement.query(By.css('.igx-calendar-view__item--selected')); - expect(highlightedMonth.nativeElement).not.toBe(initiallyHighlightedMonth.nativeElement); - expect(highlightedMonth.nativeElement.textContent.trim()).toBe('Mar'); - }); - }); }); @Component({ @@ -781,3 +755,31 @@ export class IgxMonthPickerSampleComponent { year: 'numeric' }; } + +describe('IgxMonthPicker in zoneless change detection', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [NoopAnimationsModule, IgxMonthPickerSampleComponent], + providers: [provideZonelessChangeDetection()] + }).compileComponents(); + }); + + it('should update the highlighted month after keyboard navigation', async () => { + const fixture = TestBed.createComponent(IgxMonthPickerSampleComponent); + fixture.detectChanges(); + await fixture.whenStable(); + + const monthPicker = fixture.componentInstance.monthPicker; + const wrapper = fixture.debugElement.query(By.css('.igx-calendar__wrapper')); + wrapper.nativeElement.focus(); + await fixture.whenStable(); + const initiallyHighlightedMonth = fixture.debugElement.query(By.css('.igx-calendar-view__item--selected')); + UIInteractions.triggerKeyDownEvtUponElem('ArrowRight', wrapper.nativeElement); + await fixture.whenStable(); + + expect(monthPicker.monthsView.date.getMonth()).toBe(2); + const highlightedMonth = fixture.debugElement.query(By.css('.igx-calendar-view__item--selected')); + expect(highlightedMonth.nativeElement).not.toBe(initiallyHighlightedMonth.nativeElement); + expect(highlightedMonth.nativeElement.textContent.trim()).toBe('Mar'); + }); +});