Skip to content

Commit

Permalink
fix(date-picker): add null check for optional date control (#1051)
Browse files Browse the repository at this point in the history
  • Loading branch information
twittwer authored Nov 14, 2023
1 parent 4576ce1 commit df02084
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 17 deletions.
2 changes: 1 addition & 1 deletion projects/angular/clarity.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4822,7 +4822,7 @@ export function ToggleServiceFactory(): BehaviorSubject<boolean>;

// @public (undocumented)
export class WrappedFormControl<W extends DynamicWrapper> implements OnInit, OnDestroy {
constructor(vcr: ViewContainerRef, wrapperType: Type<W>, injector: Injector, ngControl: NgControl, renderer: Renderer2, el: ElementRef);
constructor(vcr: ViewContainerRef, wrapperType: Type<W>, injector: Injector, ngControl: NgControl | null, renderer: Renderer2, el: ElementRef);
// (undocumented)
protected controlIdService: ControlIdService;
// (undocumented)
Expand Down
10 changes: 6 additions & 4 deletions projects/angular/src/forms/common/wrapped-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export class WrappedFormControl<W extends DynamicWrapper> implements OnInit, OnD
protected vcr: ViewContainerRef,
protected wrapperType: Type<W>,
injector: Injector,
private ngControl: NgControl,
private ngControl: NgControl | null,
renderer: Renderer2,
el: ElementRef
) {
Expand Down Expand Up @@ -115,7 +115,7 @@ export class WrappedFormControl<W extends DynamicWrapper> implements OnInit, OnD
this._id = this.controlIdService.id;
}

if (this.ngControlService) {
if (this.ngControlService && this.ngControl) {
this.ngControlService.setControl(this.ngControl);
}
}
Expand Down Expand Up @@ -144,8 +144,10 @@ export class WrappedFormControl<W extends DynamicWrapper> implements OnInit, OnD
}

private markAsTouched(): void {
this.ngControl.control.markAsTouched();
this.ngControl.control.updateValueAndValidity();
if (this.ngControl) {
this.ngControl.control.markAsTouched();
this.ngControl.control.updateValueAndValidity();
}
}

private setAriaDescribedBy(helpers: Helpers) {
Expand Down
46 changes: 34 additions & 12 deletions projects/angular/src/forms/datepicker/date-input.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* The full license information can be found in LICENSE in the root directory of this project.
*/

import { Component, DebugElement, Injectable, ViewChild } from '@angular/core';
import { Component, DebugElement, ViewChild } from '@angular/core';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { FormControl, FormGroup, FormsModule, NgControl, NgForm, ReactiveFormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';
Expand Down Expand Up @@ -43,16 +43,10 @@ export default function () {
let controlClassService: ControlClassService;
let datepickerFocusService: DatepickerFocusService;
let ifControlStateService: IfControlStateService;
const setControlSpy = jasmine.createSpy();

@Injectable()
class MockNgControlService extends NgControlService {
setControl = setControlSpy;
}

const DATEPICKER_PROVIDERS: any[] = [
ControlClassService,
{ provide: NgControlService, useClass: MockNgControlService },
NgControlService,
NgControl,
LayoutService,
IfControlStateService,
Expand Down Expand Up @@ -106,10 +100,6 @@ export default function () {
expect(controlClassService.className).toContain('test-class');
});

it('should set the control on NgControlService', () => {
expect(setControlSpy).toHaveBeenCalled();
});

it('should handle focus and blur events', () => {
let focusState;
const sub = focusService.focusChange.subscribe(state => (focusState = state));
Expand Down Expand Up @@ -363,16 +353,24 @@ export default function () {
beforeEach(function () {
TestBed.configureTestingModule({
imports: [FormsModule, ClrFormsModule],
providers: [NgControlService],
declarations: [TestComponentWithNgModel],
});

spyOn(TestBed.inject(NgControlService), 'setControl');

fixture = TestBed.createComponent(TestComponentWithNgModel);
fixture.detectChanges();

dateContainerDebugElement = fixture.debugElement.query(By.directive(ClrDateContainer));
dateInputDebugElement = fixture.debugElement.query(By.directive(ClrDateInput));
dateNavigationService = dateContainerDebugElement.injector.get(DateNavigationService);
});

it('should set control on NgControlService', fakeAsync(() => {
expect(TestBed.inject(NgControlService).setControl).toHaveBeenCalled();
}));

it('updates the selectedDay when the app changes the ngModel value', fakeAsync(() => {
fixture.componentInstance.dateValue = '01/02/2015';

Expand Down Expand Up @@ -479,17 +477,25 @@ export default function () {
beforeEach(function () {
TestBed.configureTestingModule({
imports: [ReactiveFormsModule, ClrFormsModule],
providers: [NgControlService],
declarations: [TestComponentWithReactiveForms],
});

spyOn(TestBed.inject(NgControlService), 'setControl');

fixture = TestBed.createComponent(TestComponentWithReactiveForms);
fixture.detectChanges();

dateContainerDebugElement = fixture.debugElement.query(By.directive(ClrDateContainer));
dateInputDebugElement = fixture.debugElement.query(By.directive(ClrDateInput));
dateNavigationService = dateContainerDebugElement.injector.get(DateNavigationService);
dateFormControlService = dateContainerDebugElement.injector.get(DateFormControlService);
});

it('should set control on NgControlService', fakeAsync(() => {
expect(TestBed.inject(NgControlService).setControl).toHaveBeenCalled();
}));

it('initializes the input and the selected day with the value set by the user', () => {
expect(fixture.componentInstance.testForm.get('date').value).not.toBeNull();

Expand Down Expand Up @@ -558,15 +564,23 @@ export default function () {
beforeEach(function () {
TestBed.configureTestingModule({
imports: [FormsModule, ClrFormsModule],
providers: [NgControlService],
declarations: [TestComponentWithTemplateDrivenForms],
});

spyOn(TestBed.inject(NgControlService), 'setControl');

fixture = TestBed.createComponent(TestComponentWithTemplateDrivenForms);
fixture.detectChanges();

dateContainerDebugElement = fixture.debugElement.query(By.directive(ClrDateContainer));
dateFormControlService = dateContainerDebugElement.injector.get(DateFormControlService);
});

it('should set control on NgControlService', fakeAsync(() => {
expect(TestBed.inject(NgControlService).setControl).toHaveBeenCalled();
}));

it('marks the form as touched when the markAsTouched event is received', done => {
fixture.whenStable().then(() => {
const form = fixture.componentInstance.templateForm.form;
Expand Down Expand Up @@ -626,16 +640,24 @@ export default function () {
beforeEach(function () {
TestBed.configureTestingModule({
imports: [FormsModule, ClrFormsModule],
providers: [NgControlService],
declarations: [TestComponentWithClrDate],
});

spyOn(TestBed.inject(NgControlService), 'setControl');

fixture = TestBed.createComponent(TestComponentWithClrDate);
fixture.detectChanges();

dateContainerDebugElement = fixture.debugElement.query(By.directive(ClrDateContainer));
dateInputDebugElement = fixture.debugElement.query(By.directive(ClrDateInput));
dateNavigationService = dateContainerDebugElement.injector.get(DateNavigationService);
});

it('should not set control on NgControlService', fakeAsync(() => {
expect(TestBed.inject(NgControlService).setControl).not.toHaveBeenCalled();
}));

it('when disabled is true there must be attribute attached to the input', () => {
fixture.componentInstance.disabled = true;
fixture.detectChanges();
Expand Down

0 comments on commit df02084

Please sign in to comment.