From 33972106ad33a2cb67236f78b8c4ca44caa2da91 Mon Sep 17 00:00:00 2001 From: Aliullov Vlad <91639107+GoodDayForSurf@users.noreply.github.com> Date: Tue, 24 Oct 2023 17:53:06 +0400 Subject: [PATCH] Safe check changed option when its iterable value becomes scalar (#25855) Co-authored-by: Mikhail Preyskurantov --- .../src/core/iterable-differ-helper.ts | 10 ++-- .../tests/src/ui/calendar.spec.ts | 54 +++++++++++++++++++ .../angular/src/app/app.component.html | 8 ++- playgrounds/angular/src/app/app.component.ts | 8 +++ 4 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 packages/devextreme-angular/tests/src/ui/calendar.spec.ts diff --git a/packages/devextreme-angular/src/core/iterable-differ-helper.ts b/packages/devextreme-angular/src/core/iterable-differ-helper.ts index 52b535f5e335..0bcc4a9a24b6 100644 --- a/packages/devextreme-angular/src/core/iterable-differ-helper.ts +++ b/packages/devextreme-angular/src/core/iterable-differ-helper.ts @@ -8,6 +8,9 @@ import { DxComponent, } from './component'; +function isIterable(value) { + return value && (typeof value[Symbol.iterator] === 'function'); +} @Injectable() export class IterableDifferHelper { private _host: DxComponent; @@ -53,12 +56,11 @@ export class IterableDifferHelper { } doCheck(prop: string) { - if (this._propertyDiffers[prop]) { + if (this._propertyDiffers[prop] && this._host.instance) { const hostValue = this._host[prop]; - const isChangedOption = this.checkChangedOptions(prop, hostValue); + const changes = isIterable(hostValue) && this.getChanges(prop, hostValue); - const changes = this.getChanges(prop, hostValue); - if (changes && this._host.instance && !isChangedOption) { + if (changes && !this.checkChangedOptions(prop, hostValue)) { this._host.lockWidgetUpdate(); this._host.instance.option(prop, hostValue); } diff --git a/packages/devextreme-angular/tests/src/ui/calendar.spec.ts b/packages/devextreme-angular/tests/src/ui/calendar.spec.ts new file mode 100644 index 000000000000..567486fd7214 --- /dev/null +++ b/packages/devextreme-angular/tests/src/ui/calendar.spec.ts @@ -0,0 +1,54 @@ +/* tslint:disable:component-selector */ + +import { + Component, + ViewChild +} from '@angular/core'; + +import { TestBed } from '@angular/core/testing'; +import { BrowserTransferStateModule } from '@angular/platform-browser'; + +import { + DxCalendarModule, + DxCalendarComponent, +} from "devextreme-angular"; + +@Component({ + selector: 'test-container-component', + template: '', +}) +class TestContainerComponent { + @ViewChild(DxCalendarComponent) calendar: DxCalendarComponent; + + value: any = []; +} + +describe('DxCalendar', () => { + beforeEach(() => { + TestBed.configureTestingModule( + { + declarations: [TestContainerComponent], + imports: [DxCalendarModule, BrowserTransferStateModule] + }); + }); + + // spec + it('should accept iterable and non-iterable values without exception', () => { + TestBed.overrideComponent(TestContainerComponent, { + set: { + template: `` + } + }); + + const fixture = TestBed.createComponent(TestContainerComponent); + + fixture.detectChanges(); + + const calendar = fixture.componentInstance.calendar; + + calendar.selectionMode = 'single'; + calendar.instance.option('value', new Date()); + + fixture.detectChanges(); + }); +}); diff --git a/playgrounds/angular/src/app/app.component.html b/playgrounds/angular/src/app/app.component.html index d246ec0cd808..b82d5d39dd1f 100644 --- a/playgrounds/angular/src/app/app.component.html +++ b/playgrounds/angular/src/app/app.component.html @@ -119,7 +119,13 @@

Editor Widgets

- + + + +

Custom Templates

diff --git a/playgrounds/angular/src/app/app.component.ts b/playgrounds/angular/src/app/app.component.ts index 6d45d7560ec3..dbc6837bb011 100644 --- a/playgrounds/angular/src/app/app.component.ts +++ b/playgrounds/angular/src/app/app.component.ts @@ -99,6 +99,14 @@ import { }) export class AppComponent implements OnInit, AfterViewInit { @ViewChild(DxPopoverComponent) popover: DxPopoverComponent; + + value: any = [ + new Date(), + new Date(new Date().getTime() + 1000 * 60 * 60 * 24) + ]; + selectionModes: string[] = ["single", "multiple", "range"]; + selectionMode = "multiple"; + text = 'Initial text'; formData = { email: '', password: '' }; emailControl: AbstractControl;