From a2f88a56558726508612f7afc0af37d5a67ccb14 Mon Sep 17 00:00:00 2001 From: Santiago Granada Date: Thu, 5 Feb 2026 23:34:36 -0800 Subject: [PATCH] fix: use $index tracking in @for loops to prevent DST duplicate key errors During DST transitions, two consecutive local hours can map to the same UTC timestamp (e.g. 2 AM CET and 3 AM CEST both become 2024-03-31T01:00:00.000Z). The @for track expressions used .toISOString() which converts to UTC, causing NG0955 when daysInWeek spans a DST boundary. Replace all .toISOString() track expressions in the week view with $index. This is safe because views are fully recomputed on every input change. Fixes #1793 --- .../calendar-week-view-header.component.ts | 2 +- .../calendar-week-view.component.spec.ts | 21 +++++++++++++++ .../calendar-week-view.component.ts | 27 +++++-------------- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/projects/angular-calendar/src/modules/week/calendar-week-view/calendar-week-view-header/calendar-week-view-header.component.ts b/projects/angular-calendar/src/modules/week/calendar-week-view/calendar-week-view-header/calendar-week-view-header.component.ts index 004ecd12a..113f2fe49 100644 --- a/projects/angular-calendar/src/modules/week/calendar-week-view/calendar-week-view-header/calendar-week-view-header.component.ts +++ b/projects/angular-calendar/src/modules/week/calendar-week-view/calendar-week-view-header/calendar-week-view-header.component.ts @@ -23,7 +23,7 @@ import { CalendarDatePipe } from '../../../common/calendar-date/calendar-date.pi let-dragEnter="dragEnter" >
- @for (day of days; track day.date.toISOString()) { + @for (day of days; track $index) {
{ expect(eventDropped).to.have.been.calledOnce; }); }); + + it('should not produce duplicate track keys when daysInWeek spans a DST transition', () => { + const fixture: ComponentFixture = + TestBed.createComponent(CalendarWeekViewComponent); + fixture.componentInstance.viewDate = new Date('2024-01-01'); + fixture.componentInstance.daysInWeek = 140; + fixture.componentInstance.events = []; + fixture.componentInstance.ngOnChanges({ + daysInWeek: {}, + events: {}, + viewDate: {}, + }); + fixture.detectChanges(); + expect( + fixture.nativeElement.querySelectorAll('.cal-header').length, + ).to.equal(140); + expect( + fixture.nativeElement.querySelectorAll('.cal-time-events .cal-day-column') + .length, + ).to.equal(140); + }); }); diff --git a/projects/angular-calendar/src/modules/week/calendar-week-view/calendar-week-view.component.ts b/projects/angular-calendar/src/modules/week/calendar-week-view/calendar-week-view.component.ts index 35f76390a..fee96527c 100644 --- a/projects/angular-calendar/src/modules/week/calendar-week-view/calendar-week-view.component.ts +++ b/projects/angular-calendar/src/modules/week/calendar-week-view/calendar-week-view.component.ts @@ -112,7 +112,7 @@ export interface CalendarWeekViewBeforeRenderEvent extends WeekView {
- @for (day of days; track day.date.toISOString()) { + @for (day of days; track $index) {
@for ( hour of view.hourColumns[0].hours; - track hour.segments[0].date.toISOString(); + track $index; let odd = $odd ) {
- @for ( - segment of hour.segments; - track segment.date.toISOString() - ) { + @for (segment of hour.segments; track $index) { - @for ( - column of view.hourColumns; - track column.hours[0] - ? column.hours[0].segments[0].date.toISOString() - : column - ) { + @for (column of view.hourColumns; track $index) {
}
- @for ( - hour of column.hours; - track hour.segments[0].date.toISOString(); - let odd = $odd - ) { + @for (hour of column.hours; track $index; let odd = $odd) {
- @for ( - segment of hour.segments; - track segment.date.toISOString() - ) { + @for (segment of hour.segments; track $index) {