Skip to content

Commit

Permalink
fix(material/datepicker): simplify DI setup
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
crisbeto committed Dec 29, 2024
1 parent 2219b11 commit 0d1e741
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 59 deletions.
60 changes: 19 additions & 41 deletions src/material/datepicker/date-range-input-parts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<D> {
id: string;
min: D | null;
max: D | null;
dateFilter: DateFilterFn<D>;
rangePicker: {
opened: boolean;
id: string;
};
// @breaking-change 20.0.0 property to become required.
_ariaOwns?: Signal<string | null>;
_startInput: MatDateRangeInputPartBase<D>;
_endInput: MatDateRangeInputPartBase<D>;
_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<MatDateRangeInputParent<unknown>>(
'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`.
Expand All @@ -70,7 +34,7 @@ abstract class MatDateRangeInputPartBase<D>
extends MatDatepickerInputBase<DateRange<D>>
implements OnInit, DoCheck
{
_rangeInput = inject<MatDateRangeInputParent<D>>(MAT_DATE_RANGE_INPUT_PARENT);
_rangeInput = inject<MatDateRangeInput<D>>(MatDateRangeInput);
override _elementRef = inject<ElementRef<HTMLInputElement>>(ElementRef);
_defaultErrorStateMatcher = inject(ErrorStateMatcher);
private _injector = inject(Injector);
Expand Down Expand Up @@ -208,7 +172,7 @@ abstract class MatDateRangeInputPartBase<D>
protected override _assignValueProgrammatically(value: D | null) {
super._assignValueProgrammatically(value);
const opposite = (
this === this._rangeInput._startInput
this === (this._rangeInput._startInput as MatDateRangeInputPartBase<D>)
? this._rangeInput._endInput
: this._rangeInput._startInput
) as MatDateRangeInputPartBase<D> | undefined;
Expand Down Expand Up @@ -261,6 +225,13 @@ export class MatStartDate<D> extends MatDateRangeInputPartBase<D> {

protected _validator = Validators.compose([...super._getValidators(), this._startValidator]);

constructor(...args: unknown[]);

constructor() {
super();
this._rangeInput._startInput = this;
}

protected _getValueFromModel(modelValue: DateRange<D>) {
return modelValue.start;
}
Expand Down Expand Up @@ -349,6 +320,13 @@ export class MatEndDate<D> extends MatDateRangeInputPartBase<D> {
: {'matEndDateInvalid': {'start': start, 'actual': end}};
};

constructor(...args: unknown[]);

constructor() {
super();
this._rangeInput._endInput = this;
}

protected _validator = Validators.compose([...super._getValidators(), this._endValidator]);

protected _getValueFromModel(modelValue: DateRange<D>) {
Expand Down
20 changes: 5 additions & 15 deletions src/material/datepicker/date-range-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ContentChild,
ElementRef,
Input,
OnChanges,
Expand All @@ -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';
Expand All @@ -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<D>
implements
MatFormFieldControl<DateRange<D>>,
MatDatepickerControl<D>,
MatDateRangeInputParent<D>,
MatDateRangePickerInput<D>,
AfterContentInit,
OnChanges,
Expand All @@ -82,6 +72,9 @@ export class MatDateRangeInput<D>
private _closedSubscription = Subscription.EMPTY;
private _openedSubscription = Subscription.EMPTY;

_startInput: MatStartDate<D>;
_endInput: MatEndDate<D>;

/** Current value of the range input. */
get value() {
return this._model ? this._model.selection : null;
Expand Down Expand Up @@ -254,9 +247,6 @@ export class MatDateRangeInput<D>
/** End of the comparison range that should be shown in the calendar. */
@Input() comparisonEnd: D | null = null;

@ContentChild(MatStartDate) _startInput: MatStartDate<D>;
@ContentChild(MatEndDate) _endInput: MatEndDate<D>;

/**
* Implemented as a part of `MatFormFieldControl`.
* TODO(crisbeto): change type to `AbstractControlDirective` after #18206 lands.
Expand Down
7 changes: 4 additions & 3 deletions tools/public_api_guard/material/datepicker.md
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -568,7 +567,7 @@ export class MatDatepickerToggleIcon {
}

// @public (undocumented)
export class MatDateRangeInput<D> implements MatFormFieldControl<DateRange<D>>, MatDatepickerControl<D>, MatDateRangeInputParent<D>, MatDateRangePickerInput<D>, AfterContentInit, OnChanges, OnDestroy {
export class MatDateRangeInput<D> implements MatFormFieldControl<DateRange<D>>, MatDatepickerControl<D>, MatDateRangePickerInput<D>, AfterContentInit, OnChanges, OnDestroy {
constructor(...args: unknown[]);
_ariaDescribedBy: string | null;
_ariaOwns: WritableSignal<string | null>;
Expand Down Expand Up @@ -632,7 +631,7 @@ export class MatDateRangeInput<D> implements MatFormFieldControl<DateRange<D>>,
_updateFocus(origin: FocusOrigin): void;
get value(): DateRange<D> | null;
// (undocumented)
static ɵcmp: i0.ɵɵComponentDeclaration<MatDateRangeInput<any>, "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<MatDateRangeInput<any>, "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<MatDateRangeInput<any>, never>;
}
Expand Down Expand Up @@ -679,6 +678,7 @@ export abstract class MatDateSelectionModel<S, D = ExtractDateTypeFromSelection<

// @public
export class MatEndDate<D> extends MatDateRangeInputPartBase<D> {
constructor(...args: unknown[]);
// (undocumented)
protected _assignValueToModel(value: D | null): void;
// (undocumented)
Expand Down Expand Up @@ -829,6 +829,7 @@ export class MatSingleDateSelectionModel<D> extends MatDateSelectionModel<D | nu

// @public
export class MatStartDate<D> extends MatDateRangeInputPartBase<D> {
constructor(...args: unknown[]);
// (undocumented)
protected _assignValueToModel(value: D | null): void;
// (undocumented)
Expand Down

0 comments on commit 0d1e741

Please sign in to comment.