From 983bb43c9400c12237c7d0b1900c0d995bc320d0 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Sun, 29 Dec 2024 21:48:47 +0100 Subject: [PATCH] fix(material/datepicker): simplify DI setup Previously we had to define an injection token for the `MatDateRangeInput` in order to avoid circular references. Now we can do the same with a type-only imports so we can simplify the setup. Fixes #30238. --- .../datepicker/date-range-input-parts.ts | 57 ++++++------------- src/material/datepicker/date-range-input.ts | 20 ++----- tools/public_api_guard/material/datepicker.md | 9 ++- 3 files changed, 27 insertions(+), 59 deletions(-) diff --git a/src/material/datepicker/date-range-input-parts.ts b/src/material/datepicker/date-range-input-parts.ts index aff57bd3ca5d..42584785b4a1 100644 --- a/src/material/datepicker/date-range-input-parts.ts +++ b/src/material/datepicker/date-range-input-parts.ts @@ -8,17 +8,7 @@ import {Directionality} from '@angular/cdk/bidi'; import {BACKSPACE, LEFT_ARROW, RIGHT_ARROW} from '@angular/cdk/keycodes'; -import { - Directive, - DoCheck, - ElementRef, - InjectionToken, - Injector, - Input, - OnInit, - Signal, - inject, -} from '@angular/core'; +import {Directive, DoCheck, ElementRef, Injector, Input, OnInit, inject} from '@angular/core'; import { AbstractControl, FormGroupDirective, @@ -33,34 +23,8 @@ import { import {ErrorStateMatcher, _ErrorStateTracker} from '@angular/material/core'; import {_computeAriaAccessibleName} from './aria-accessible-name'; import {DateRange, DateSelectionModelChange} from './date-selection-model'; -import {DateFilterFn, MatDatepickerInputBase} from './datepicker-input-base'; - -/** Parent component that should be wrapped around `MatStartDate` and `MatEndDate`. */ -export interface MatDateRangeInputParent { - id: string; - min: D | null; - max: D | null; - dateFilter: DateFilterFn; - rangePicker: { - opened: boolean; - id: string; - }; - // @breaking-change 20.0.0 property to become required. - _ariaOwns?: Signal; - _startInput: MatDateRangeInputPartBase; - _endInput: MatDateRangeInputPartBase; - _groupDisabled: boolean; - _handleChildValueChange(): void; - _openDatepicker(): void; -} - -/** - * Used to provide the date range input wrapper component - * to the parts without circular dependencies. - */ -export const MAT_DATE_RANGE_INPUT_PARENT = new InjectionToken>( - 'MAT_DATE_RANGE_INPUT_PARENT', -); +import {MatDatepickerInputBase} from './datepicker-input-base'; +import {MatDateRangeInput} from './date-range-input'; /** * Base class for the individual inputs that can be projected inside a `mat-date-range-input`. @@ -70,7 +34,7 @@ abstract class MatDateRangeInputPartBase extends MatDatepickerInputBase> implements OnInit, DoCheck { - _rangeInput = inject>(MAT_DATE_RANGE_INPUT_PARENT); + _rangeInput = inject>(MatDateRangeInput); override _elementRef = inject>(ElementRef); _defaultErrorStateMatcher = inject(ErrorStateMatcher); private _injector = inject(Injector); @@ -86,6 +50,7 @@ abstract class MatDateRangeInputPartBase protected abstract override _validator: ValidatorFn | null; protected abstract override _assignValueToModel(value: D | null): void; protected abstract override _getValueFromModel(modelValue: DateRange): D | null; + protected abstract _register(): void; protected readonly _dir = inject(Directionality, {optional: true}); private _errorStateTracker: _ErrorStateTracker; @@ -133,6 +98,8 @@ abstract class MatDateRangeInputPartBase this.ngControl = ngControl; this._errorStateTracker.ngControl = ngControl; } + + this._register(); } ngDoCheck() { @@ -208,7 +175,7 @@ abstract class MatDateRangeInputPartBase protected override _assignValueProgrammatically(value: D | null) { super._assignValueProgrammatically(value); const opposite = ( - this === this._rangeInput._startInput + this === (this._rangeInput._startInput as MatDateRangeInputPartBase) ? this._rangeInput._endInput : this._rangeInput._startInput ) as MatDateRangeInputPartBase | undefined; @@ -261,6 +228,10 @@ export class MatStartDate extends MatDateRangeInputPartBase { protected _validator = Validators.compose([...super._getValidators(), this._startValidator]); + protected override _register(): void { + this._rangeInput._startInput = this; + } + protected _getValueFromModel(modelValue: DateRange) { return modelValue.start; } @@ -349,6 +320,10 @@ export class MatEndDate extends MatDateRangeInputPartBase { : {'matEndDateInvalid': {'start': start, 'actual': end}}; }; + protected override _register(): void { + this._rangeInput._endInput = this; + } + protected _validator = Validators.compose([...super._getValidators(), this._endValidator]); protected _getValueFromModel(modelValue: DateRange) { diff --git a/src/material/datepicker/date-range-input.ts b/src/material/datepicker/date-range-input.ts index 935726662b54..695c08b43308 100644 --- a/src/material/datepicker/date-range-input.ts +++ b/src/material/datepicker/date-range-input.ts @@ -12,7 +12,6 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - ContentChild, ElementRef, Input, OnChanges, @@ -27,12 +26,7 @@ import {ControlContainer, NgControl, Validators} from '@angular/forms'; import {DateAdapter, ThemePalette} from '@angular/material/core'; import {MAT_FORM_FIELD, MatFormFieldControl} from '@angular/material/form-field'; import {Subject, Subscription, merge} from 'rxjs'; -import { - MAT_DATE_RANGE_INPUT_PARENT, - MatDateRangeInputParent, - MatEndDate, - MatStartDate, -} from './date-range-input-parts'; +import type {MatEndDate, MatStartDate} from './date-range-input-parts'; import {MatDateRangePickerInput} from './date-range-picker'; import {DateRange, MatDateSelectionModel} from './date-selection-model'; import {MatDatepickerControl, MatDatepickerPanel} from './datepicker-base'; @@ -58,17 +52,13 @@ import {DateFilterFn, _MatFormFieldPartial, dateInputsHaveChanged} from './datep }, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, - providers: [ - {provide: MatFormFieldControl, useExisting: MatDateRangeInput}, - {provide: MAT_DATE_RANGE_INPUT_PARENT, useExisting: MatDateRangeInput}, - ], + providers: [{provide: MatFormFieldControl, useExisting: MatDateRangeInput}], imports: [CdkMonitorFocus], }) export class MatDateRangeInput implements MatFormFieldControl>, MatDatepickerControl, - MatDateRangeInputParent, MatDateRangePickerInput, AfterContentInit, OnChanges, @@ -82,6 +72,9 @@ export class MatDateRangeInput private _closedSubscription = Subscription.EMPTY; private _openedSubscription = Subscription.EMPTY; + _startInput: MatStartDate; + _endInput: MatEndDate; + /** Current value of the range input. */ get value() { return this._model ? this._model.selection : null; @@ -254,9 +247,6 @@ export class MatDateRangeInput /** End of the comparison range that should be shown in the calendar. */ @Input() comparisonEnd: D | null = null; - @ContentChild(MatStartDate) _startInput: MatStartDate; - @ContentChild(MatEndDate) _endInput: MatEndDate; - /** * Implemented as a part of `MatFormFieldControl`. * TODO(crisbeto): change type to `AbstractControlDirective` after #18206 lands. diff --git a/tools/public_api_guard/material/datepicker.md b/tools/public_api_guard/material/datepicker.md index 3123e6584977..e36f6f9de145 100644 --- a/tools/public_api_guard/material/datepicker.md +++ b/tools/public_api_guard/material/datepicker.md @@ -41,7 +41,6 @@ import { OnInit } from '@angular/core'; import { Overlay } from '@angular/cdk/overlay'; import { Portal } from '@angular/cdk/portal'; import { ScrollStrategy } from '@angular/cdk/overlay'; -import { Signal } from '@angular/core'; import { SimpleChanges } from '@angular/core'; import { Subject } from 'rxjs'; import { TemplatePortal } from '@angular/cdk/portal'; @@ -568,7 +567,7 @@ export class MatDatepickerToggleIcon { } // @public (undocumented) -export class MatDateRangeInput implements MatFormFieldControl>, MatDatepickerControl, MatDateRangeInputParent, MatDateRangePickerInput, AfterContentInit, OnChanges, OnDestroy { +export class MatDateRangeInput implements MatFormFieldControl>, MatDatepickerControl, MatDateRangePickerInput, AfterContentInit, OnChanges, OnDestroy { constructor(...args: unknown[]); _ariaDescribedBy: string | null; _ariaOwns: WritableSignal; @@ -632,7 +631,7 @@ export class MatDateRangeInput implements MatFormFieldControl>, _updateFocus(origin: FocusOrigin): void; get value(): DateRange | null; // (undocumented) - static ɵcmp: i0.ɵɵComponentDeclaration, "mat-date-range-input", ["matDateRangeInput"], { "rangePicker": { "alias": "rangePicker"; "required": false; }; "required": { "alias": "required"; "required": false; }; "dateFilter": { "alias": "dateFilter"; "required": false; }; "min": { "alias": "min"; "required": false; }; "max": { "alias": "max"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "separator": { "alias": "separator"; "required": false; }; "comparisonStart": { "alias": "comparisonStart"; "required": false; }; "comparisonEnd": { "alias": "comparisonEnd"; "required": false; }; }, {}, ["_startInput", "_endInput"], ["input[matStartDate]", "input[matEndDate]"], true, never>; + static ɵcmp: i0.ɵɵComponentDeclaration, "mat-date-range-input", ["matDateRangeInput"], { "rangePicker": { "alias": "rangePicker"; "required": false; }; "required": { "alias": "required"; "required": false; }; "dateFilter": { "alias": "dateFilter"; "required": false; }; "min": { "alias": "min"; "required": false; }; "max": { "alias": "max"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "separator": { "alias": "separator"; "required": false; }; "comparisonStart": { "alias": "comparisonStart"; "required": false; }; "comparisonEnd": { "alias": "comparisonEnd"; "required": false; }; }, {}, never, ["input[matStartDate]", "input[matEndDate]"], true, never>; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration, never>; } @@ -686,6 +685,8 @@ export class MatEndDate extends MatDateRangeInputPartBase { // (undocumented) _onKeydown(event: KeyboardEvent): void; // (undocumented) + protected _register(): void; + // (undocumented) protected _shouldHandleChangeEvent(change: DateSelectionModelChange>): boolean; // (undocumented) protected _validator: ValidatorFn | null; @@ -838,6 +839,8 @@ export class MatStartDate extends MatDateRangeInputPartBase { // (undocumented) _onKeydown(event: KeyboardEvent): void; // (undocumented) + protected _register(): void; + // (undocumented) protected _shouldHandleChangeEvent(change: DateSelectionModelChange>): boolean; // (undocumented) protected _validator: ValidatorFn | null;