Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(material/datepicker): simplify DI setup #30247

Merged
merged 1 commit into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 19 additions & 33 deletions src/material/datepicker/date-range-input-parts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@
import {Directionality} from '@angular/cdk/bidi';
import {BACKSPACE, LEFT_ARROW, RIGHT_ARROW} from '@angular/cdk/keycodes';
import {
AfterContentInit,
Directive,
DoCheck,
ElementRef,
InjectionToken,
Injector,
Input,
OnInit,
Signal,
inject,
} from '@angular/core';
import {
Expand All @@ -33,44 +32,18 @@ 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`.
*/
@Directive()
abstract class MatDateRangeInputPartBase<D>
extends MatDatepickerInputBase<DateRange<D>>
implements OnInit, DoCheck
implements OnInit, AfterContentInit, 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 All @@ -86,6 +59,7 @@ abstract class MatDateRangeInputPartBase<D>
protected abstract override _validator: ValidatorFn | null;
protected abstract override _assignValueToModel(value: D | null): void;
protected abstract override _getValueFromModel(modelValue: DateRange<D>): D | null;
protected abstract _register(): void;
protected readonly _dir = inject(Directionality, {optional: true});
private _errorStateTracker: _ErrorStateTracker;

Expand Down Expand Up @@ -135,6 +109,10 @@ abstract class MatDateRangeInputPartBase<D>
}
}

ngAfterContentInit(): void {
this._register();
}

ngDoCheck() {
if (this.ngControl) {
// We need to re-evaluate this on every change detection cycle, because there are some
Expand Down Expand Up @@ -208,7 +186,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 +239,10 @@ export class MatStartDate<D> extends MatDateRangeInputPartBase<D> {

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

protected override _register(): void {
this._rangeInput._startInput = this;
}

protected _getValueFromModel(modelValue: DateRange<D>) {
return modelValue.start;
}
Expand Down Expand Up @@ -349,6 +331,10 @@ export class MatEndDate<D> extends MatDateRangeInputPartBase<D> {
: {'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<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
9 changes: 6 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 @@ -686,6 +685,8 @@ export class MatEndDate<D> extends MatDateRangeInputPartBase<D> {
// (undocumented)
_onKeydown(event: KeyboardEvent): void;
// (undocumented)
protected _register(): void;
// (undocumented)
protected _shouldHandleChangeEvent(change: DateSelectionModelChange<DateRange<D>>): boolean;
// (undocumented)
protected _validator: ValidatorFn | null;
Expand Down Expand Up @@ -838,6 +839,8 @@ export class MatStartDate<D> extends MatDateRangeInputPartBase<D> {
// (undocumented)
_onKeydown(event: KeyboardEvent): void;
// (undocumented)
protected _register(): void;
// (undocumented)
protected _shouldHandleChangeEvent(change: DateSelectionModelChange<DateRange<D>>): boolean;
// (undocumented)
protected _validator: ValidatorFn | null;
Expand Down
Loading