Skip to content

Commit 5897f37

Browse files
authored
refactor(multiple): switch material to the inject function (#29731)
Switches Material from constructor-based DI to the `inject` function.
1 parent 886fb6d commit 5897f37

File tree

144 files changed

+1425
-2111
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

144 files changed

+1425
-2111
lines changed

src/cdk/a11y/aria-describer/aria-describer.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,7 @@ export class AriaDescriber implements OnDestroy {
207207
messagesContainer.classList.add(containerClassName);
208208
messagesContainer.classList.add('cdk-visually-hidden');
209209

210-
// @breaking-change 14.0.0 Remove null check for `_platform`.
211-
if (this._platform && !this._platform.isBrowser) {
210+
if (!this._platform.isBrowser) {
212211
messagesContainer.setAttribute('platform', 'server');
213212
}
214213

src/cdk/portal/dom-portal-outlet.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,12 +150,6 @@ export class DomPortalOutlet extends BasePortalOutlet {
150150
* @breaking-change 10.0.0
151151
*/
152152
override attachDomPortal = (portal: DomPortal) => {
153-
// @breaking-change 10.0.0 Remove check and error once the
154-
// `_document` constructor parameter is required.
155-
if (!this._document && (typeof ngDevMode === 'undefined' || ngDevMode)) {
156-
throw Error('Cannot attach DOM portal without _document constructor parameter');
157-
}
158-
159153
const element = portal.element;
160154
if (!element.parentNode && (typeof ngDevMode === 'undefined' || ngDevMode)) {
161155
throw Error('DOM portal content must be attached to a parent node.');

src/cdk/portal/portal-directives.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -201,12 +201,6 @@ export class CdkPortalOutlet extends BasePortalOutlet implements OnInit, OnDestr
201201
* @breaking-change 10.0.0
202202
*/
203203
override attachDomPortal = (portal: DomPortal) => {
204-
// @breaking-change 9.0.0 Remove check and error once the
205-
// `_document` constructor parameter is required.
206-
if (!this._document && (typeof ngDevMode === 'undefined' || ngDevMode)) {
207-
throw Error('Cannot attach DOM portal without _document constructor parameter');
208-
}
209-
210204
const element = portal.element;
211205
if (!element.parentNode && (typeof ngDevMode === 'undefined' || ngDevMode)) {
212206
throw Error('DOM portal content must be attached to a parent node.');

src/material-date-fns-adapter/adapter/date-fns-adapter.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Inject, Injectable, Optional} from '@angular/core';
9+
import {Injectable, inject} from '@angular/core';
1010
import {DateAdapter, MAT_DATE_LOCALE} from '@angular/material/core';
1111
import {
1212
Locale,
@@ -52,8 +52,11 @@ const DAY_OF_WEEK_FORMATS = {
5252
/** Adds date-fns support to Angular Material. */
5353
@Injectable()
5454
export class DateFnsAdapter extends DateAdapter<Date, Locale> {
55-
constructor(@Optional() @Inject(MAT_DATE_LOCALE) matDateLocale: {}) {
55+
constructor(...args: unknown[]);
56+
57+
constructor() {
5658
super();
59+
const matDateLocale = inject(MAT_DATE_LOCALE, {optional: true});
5760
this.setLocale(matDateLocale as Locale);
5861
}
5962

src/material-luxon-adapter/adapter/luxon-date-adapter.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Inject, Injectable, Optional, InjectionToken} from '@angular/core';
9+
import {Injectable, InjectionToken, inject} from '@angular/core';
1010
import {DateAdapter, MAT_DATE_LOCALE} from '@angular/material/core';
1111
import {
1212
DateTime as LuxonDateTime,
@@ -70,13 +70,16 @@ export class LuxonDateAdapter extends DateAdapter<LuxonDateTime> {
7070
private _firstDayOfWeek: number;
7171
private _defaultOutputCalendar: LuxonCalendarSystem;
7272

73-
constructor(
74-
@Optional() @Inject(MAT_DATE_LOCALE) dateLocale: string,
75-
@Optional()
76-
@Inject(MAT_LUXON_DATE_ADAPTER_OPTIONS)
77-
options?: MatLuxonDateAdapterOptions,
78-
) {
73+
constructor(...args: unknown[]);
74+
75+
constructor() {
7976
super();
77+
78+
const dateLocale = inject(MAT_DATE_LOCALE, {optional: true});
79+
const options = inject<MatLuxonDateAdapterOptions>(MAT_LUXON_DATE_ADAPTER_OPTIONS, {
80+
optional: true,
81+
});
82+
8083
this._useUTC = !!options?.useUtc;
8184
this._firstDayOfWeek = options?.firstDayOfWeek || 0;
8285
this._defaultOutputCalendar = options?.defaultOutputCalendar || 'gregory';

src/material-moment-adapter/adapter/moment-date-adapter.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Inject, Injectable, Optional, InjectionToken} from '@angular/core';
9+
import {Injectable, InjectionToken, inject} from '@angular/core';
1010
import {DateAdapter, MAT_DATE_LOCALE} from '@angular/material/core';
1111
// Depending on whether rollup is used, moment needs to be imported differently.
1212
// Since Moment.js doesn't have a default export, we normally need to import using the `* as`
@@ -63,6 +63,10 @@ function range<T>(length: number, valueFunction: (index: number) => T): T[] {
6363
/** Adapts Moment.js Dates for use with Angular Material. */
6464
@Injectable()
6565
export class MomentDateAdapter extends DateAdapter<Moment> {
66+
private _options = inject<MatMomentDateAdapterOptions>(MAT_MOMENT_DATE_ADAPTER_OPTIONS, {
67+
optional: true,
68+
});
69+
6670
// Note: all of the methods that accept a `Moment` input parameter immediately call `this.clone`
6771
// on it. This is to ensure that we're working with a `Moment` that has the correct locale setting
6872
// while avoiding mutating the original object passed to us. Just calling `.locale(...)` on the
@@ -78,13 +82,11 @@ export class MomentDateAdapter extends DateAdapter<Moment> {
7882
narrowDaysOfWeek: string[];
7983
};
8084

81-
constructor(
82-
@Optional() @Inject(MAT_DATE_LOCALE) dateLocale: string,
83-
@Optional()
84-
@Inject(MAT_MOMENT_DATE_ADAPTER_OPTIONS)
85-
private _options?: MatMomentDateAdapterOptions,
86-
) {
85+
constructor(...args: unknown[]);
86+
87+
constructor() {
8788
super();
89+
const dateLocale = inject<string>(MAT_DATE_LOCALE, {optional: true});
8890
this.setLocale(dateLocale || moment.locale());
8991
}
9092

src/material/autocomplete/autocomplete-origin.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Directive, ElementRef} from '@angular/core';
9+
import {Directive, ElementRef, inject} from '@angular/core';
1010

1111
/**
1212
* Directive applied to an element to make it usable
@@ -18,8 +18,8 @@ import {Directive, ElementRef} from '@angular/core';
1818
standalone: true,
1919
})
2020
export class MatAutocompleteOrigin {
21-
constructor(
22-
/** Reference to the element on which the directive is applied. */
23-
public elementRef: ElementRef<HTMLElement>,
24-
) {}
21+
elementRef = inject<ElementRef<HTMLElement>>(ElementRef);
22+
23+
constructor(...args: unknown[]);
24+
constructor() {}
2525
}

src/material/autocomplete/autocomplete-trigger.ts

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,12 @@ import {
2828
ChangeDetectorRef,
2929
Directive,
3030
ElementRef,
31-
Host,
32-
Inject,
3331
InjectionToken,
3432
Injector,
3533
Input,
3634
NgZone,
3735
OnChanges,
3836
OnDestroy,
39-
Optional,
4037
SimpleChanges,
4138
ViewContainerRef,
4239
afterNextRender,
@@ -134,10 +131,24 @@ export const MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY_PROVIDER = {
134131
export class MatAutocompleteTrigger
135132
implements ControlValueAccessor, AfterViewInit, OnChanges, OnDestroy
136133
{
134+
private _element = inject<ElementRef<HTMLInputElement>>(ElementRef);
135+
private _overlay = inject(Overlay);
136+
private _viewContainerRef = inject(ViewContainerRef);
137+
private _zone = inject(NgZone);
138+
private _changeDetectorRef = inject(ChangeDetectorRef);
139+
private _dir = inject(Directionality, {optional: true});
140+
private _formField = inject<MatFormField | null>(MAT_FORM_FIELD, {optional: true, host: true});
141+
private _document = inject(DOCUMENT);
142+
private _viewportRuler = inject(ViewportRuler);
143+
private _defaults = inject<MatAutocompleteDefaultOptions | null>(
144+
MAT_AUTOCOMPLETE_DEFAULT_OPTIONS,
145+
{optional: true},
146+
);
147+
137148
private _overlayRef: OverlayRef | null;
138149
private _portal: TemplatePortal;
139150
private _componentDestroyed = false;
140-
private _scrollStrategy: () => ScrollStrategy;
151+
private _scrollStrategy = inject(MAT_AUTOCOMPLETE_SCROLL_STRATEGY);
141152
private _keydownSubscription: Subscription | null;
142153
private _outsideClickSubscription: Subscription | null;
143154

@@ -238,23 +249,8 @@ export class MatAutocompleteTrigger
238249

239250
private _injector = inject(Injector);
240251

241-
constructor(
242-
private _element: ElementRef<HTMLInputElement>,
243-
private _overlay: Overlay,
244-
private _viewContainerRef: ViewContainerRef,
245-
private _zone: NgZone,
246-
private _changeDetectorRef: ChangeDetectorRef,
247-
@Inject(MAT_AUTOCOMPLETE_SCROLL_STRATEGY) scrollStrategy: any,
248-
@Optional() private _dir: Directionality | null,
249-
@Optional() @Inject(MAT_FORM_FIELD) @Host() private _formField: MatFormField | null,
250-
@Optional() @Inject(DOCUMENT) private _document: any,
251-
private _viewportRuler: ViewportRuler,
252-
@Optional()
253-
@Inject(MAT_AUTOCOMPLETE_DEFAULT_OPTIONS)
254-
private _defaults?: MatAutocompleteDefaultOptions | null,
255-
) {
256-
this._scrollStrategy = scrollStrategy;
257-
}
252+
constructor(...args: unknown[]);
253+
constructor() {}
258254

259255
/** Class to apply to the panel when it's above the input. */
260256
private _aboveClass = 'mat-mdc-autocomplete-panel-above';

src/material/autocomplete/autocomplete.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import {
1414
ContentChildren,
1515
ElementRef,
1616
EventEmitter,
17-
Inject,
1817
InjectionToken,
1918
Input,
2019
OnDestroy,
@@ -24,6 +23,7 @@ import {
2423
ViewChild,
2524
ViewEncapsulation,
2625
booleanAttribute,
26+
inject,
2727
} from '@angular/core';
2828
import {AnimationEvent} from '@angular/animations';
2929
import {
@@ -119,6 +119,10 @@ export function MAT_AUTOCOMPLETE_DEFAULT_OPTIONS_FACTORY(): MatAutocompleteDefau
119119
standalone: true,
120120
})
121121
export class MatAutocomplete implements AfterContentInit, OnDestroy {
122+
private _changeDetectorRef = inject(ChangeDetectorRef);
123+
private _elementRef = inject<ElementRef<HTMLElement>>(ElementRef);
124+
protected _defaults = inject<MatAutocompleteDefaultOptions>(MAT_AUTOCOMPLETE_DEFAULT_OPTIONS);
125+
122126
private _activeOptionChanges = Subscription.EMPTY;
123127

124128
/** Emits when the panel animation is done. Null if the panel doesn't animate. */
@@ -252,20 +256,19 @@ export class MatAutocomplete implements AfterContentInit, OnDestroy {
252256
*/
253257
readonly inertGroups: boolean;
254258

255-
constructor(
256-
private _changeDetectorRef: ChangeDetectorRef,
257-
private _elementRef: ElementRef<HTMLElement>,
258-
@Inject(MAT_AUTOCOMPLETE_DEFAULT_OPTIONS) protected _defaults: MatAutocompleteDefaultOptions,
259-
platform?: Platform,
260-
) {
259+
constructor(...args: unknown[]);
260+
261+
constructor() {
262+
const platform = inject(Platform);
263+
261264
// TODO(crisbeto): the problem that the `inertGroups` option resolves is only present on
262265
// Safari using VoiceOver. We should occasionally check back to see whether the bug
263266
// wasn't resolved in VoiceOver, and if it has, we can remove this and the `inertGroups`
264267
// option altogether.
265268
this.inertGroups = platform?.SAFARI || false;
266-
this.autoActiveFirstOption = !!_defaults.autoActiveFirstOption;
267-
this.autoSelectActiveOption = !!_defaults.autoSelectActiveOption;
268-
this.requireSelection = !!_defaults.requireSelection;
269+
this.autoActiveFirstOption = !!this._defaults.autoActiveFirstOption;
270+
this.autoSelectActiveOption = !!this._defaults.autoSelectActiveOption;
271+
this.requireSelection = !!this._defaults.requireSelection;
269272
this._hideSingleSelectionIndicator = this._defaults.hideSingleSelectionIndicator ?? false;
270273
}
271274

src/material/badge/badge.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,10 @@ import {
1515
Directive,
1616
ElementRef,
1717
inject,
18-
Inject,
1918
Input,
2019
NgZone,
2120
OnDestroy,
2221
OnInit,
23-
Optional,
2422
Renderer2,
2523
ViewEncapsulation,
2624
ANIMATION_MODULE_TYPE,
@@ -78,6 +76,12 @@ export class _MatBadgeStyleLoader {}
7876
standalone: true,
7977
})
8078
export class MatBadge implements OnInit, OnDestroy {
79+
private _ngZone = inject(NgZone);
80+
private _elementRef = inject<ElementRef<HTMLElement>>(ElementRef);
81+
private _ariaDescriber = inject(AriaDescriber);
82+
private _renderer = inject(Renderer2);
83+
private _animationMode = inject(ANIMATION_MODULE_TYPE, {optional: true});
84+
8185
/**
8286
* Theme color of the badge. This API is supported in M2 themes only, it
8387
* has no effect in M3 themes.
@@ -150,18 +154,13 @@ export class MatBadge implements OnInit, OnDestroy {
150154

151155
private _document = inject(DOCUMENT);
152156

153-
constructor(
154-
private _ngZone: NgZone,
155-
private _elementRef: ElementRef<HTMLElement>,
156-
private _ariaDescriber: AriaDescriber,
157-
private _renderer: Renderer2,
158-
@Optional() @Inject(ANIMATION_MODULE_TYPE) private _animationMode?: string,
159-
) {
160-
const styleLoader = inject(_CdkPrivateStyleLoader);
161-
styleLoader.load(_MatBadgeStyleLoader);
157+
constructor(...args: unknown[]);
158+
159+
constructor() {
160+
inject(_CdkPrivateStyleLoader).load(_MatBadgeStyleLoader);
162161

163162
if (typeof ngDevMode === 'undefined' || ngDevMode) {
164-
const nativeElement = _elementRef.nativeElement;
163+
const nativeElement = this._elementRef.nativeElement;
165164
if (nativeElement.nodeType !== nativeElement.ELEMENT_NODE) {
166165
throw Error('matBadge must be attached to an element node.');
167166
}

src/material/bottom-sheet/bottom-sheet-container.ts

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,15 @@
77
*/
88

99
import {AnimationEvent} from '@angular/animations';
10-
import {CdkDialogContainer, DialogConfig} from '@angular/cdk/dialog';
11-
import {FocusMonitor, FocusTrapFactory, InteractivityChecker} from '@angular/cdk/a11y';
10+
import {CdkDialogContainer} from '@angular/cdk/dialog';
1211
import {BreakpointObserver, Breakpoints} from '@angular/cdk/layout';
13-
import {OverlayRef} from '@angular/cdk/overlay';
14-
import {DOCUMENT} from '@angular/common';
1512
import {
1613
ChangeDetectionStrategy,
1714
Component,
18-
ElementRef,
1915
EventEmitter,
20-
Inject,
21-
NgZone,
2216
OnDestroy,
23-
Optional,
2417
ViewEncapsulation,
18+
inject,
2519
} from '@angular/core';
2620
import {Subscription} from 'rxjs';
2721
import {matBottomSheetAnimations} from './bottom-sheet-animations';
@@ -67,27 +61,12 @@ export class MatBottomSheetContainer extends CdkDialogContainer implements OnDes
6761
/** Whether the component has been destroyed. */
6862
private _destroyed: boolean;
6963

70-
constructor(
71-
elementRef: ElementRef,
72-
focusTrapFactory: FocusTrapFactory,
73-
@Optional() @Inject(DOCUMENT) document: any,
74-
config: DialogConfig,
75-
checker: InteractivityChecker,
76-
ngZone: NgZone,
77-
overlayRef: OverlayRef,
78-
breakpointObserver: BreakpointObserver,
79-
focusMonitor?: FocusMonitor,
80-
) {
81-
super(
82-
elementRef,
83-
focusTrapFactory,
84-
document,
85-
config,
86-
checker,
87-
ngZone,
88-
overlayRef,
89-
focusMonitor,
90-
);
64+
constructor(...args: unknown[]);
65+
66+
constructor() {
67+
super();
68+
69+
const breakpointObserver = inject(BreakpointObserver);
9170

9271
this._breakpointSubscription = breakpointObserver
9372
.observe([Breakpoints.Medium, Breakpoints.Large, Breakpoints.XLarge])

0 commit comments

Comments
 (0)