Skip to content

Commit 8ec44a1

Browse files
authored
feat(form-field): use injection token for providing form-field (#18777)
Implementers of custom form-field controls often want to inject the parent `MatFormField` optionally. This currently has negative impact as the whole `MatFormField` class w/ Angular metadata is brought in due to the class being used as injector token. This can be avoided by using a separate thin injection token called `MAT_FORM_FIELD`. We use this now in `MatSelect`, `MatAutocompleteTrigger` and `MatChipList`. These don't necessarily require a form-field, so it's a significant bundle size improvement. Another benefit is that the MDC-based form-field no longer needs to re-provide the standard `MatFormField` w/ the downside of bringing in a lot of unnecessary code.
1 parent b2e8691 commit 8ec44a1

File tree

6 files changed

+19
-10
lines changed

6 files changed

+19
-10
lines changed

src/material-experimental/mdc-form-field/form-field.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import {
3737
import {
3838
getMatFormFieldDuplicatedHintError,
3939
getMatFormFieldMissingControlError,
40-
MatFormField as NonMdcFormField,
40+
MAT_FORM_FIELD,
4141
matFormFieldAnimations,
4242
MatFormFieldControl,
4343
} from '@angular/material/form-field';
@@ -123,9 +123,7 @@ const FLOATING_LABEL_DEFAULT_DOCKED_TRANSFORM = `translateY(-50%)`;
123123
encapsulation: ViewEncapsulation.None,
124124
changeDetection: ChangeDetectionStrategy.OnPush,
125125
providers: [
126-
// Temporary workaround that allows us to test the MDC form-field against
127-
// components which inject the non-mdc form-field (e.g. autocomplete).
128-
{provide: NonMdcFormField, useExisting: MatFormField}
126+
{provide: MAT_FORM_FIELD, useExisting: MatFormField},
129127
]
130128
})
131129
export class MatFormField implements AfterViewInit, OnDestroy, AfterContentChecked,

src/material/autocomplete/autocomplete-trigger.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ import {
4545
MatOption,
4646
MatOptionSelectionChange,
4747
} from '@angular/material/core';
48-
import {MatFormField} from '@angular/material/form-field';
48+
import {MAT_FORM_FIELD, MatFormField} from '@angular/material/form-field';
4949
import {defer, fromEvent, merge, Observable, of as observableOf, Subject, Subscription} from 'rxjs';
5050
import {delay, filter, map, switchMap, take, tap} from 'rxjs/operators';
5151

@@ -217,7 +217,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, AfterViewIn
217217
private _changeDetectorRef: ChangeDetectorRef,
218218
@Inject(MAT_AUTOCOMPLETE_SCROLL_STRATEGY) scrollStrategy: any,
219219
@Optional() private _dir: Directionality,
220-
@Optional() @Host() private _formField: MatFormField,
220+
@Optional() @Inject(MAT_FORM_FIELD) @Host() private _formField: MatFormField,
221221
@Optional() @Inject(DOCUMENT) private _document: any,
222222
// @breaking-change 8.0.0 Make `_viewportRuler` required.
223223
private _viewportRuler?: ViewportRuler) {

src/material/datepicker/datepicker-input.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import {
3030
Validators,
3131
} from '@angular/forms';
3232
import {DateAdapter, MAT_DATE_FORMATS, MatDateFormats, ThemePalette} from '@angular/material/core';
33-
import {MatFormField} from '@angular/material/form-field';
33+
import {MAT_FORM_FIELD, MatFormField} from '@angular/material/form-field';
3434
import {MAT_INPUT_VALUE_ACCESSOR} from '@angular/material/input';
3535
import {Subscription} from 'rxjs';
3636
import {MatDatepicker} from './datepicker';
@@ -243,7 +243,7 @@ export class MatDatepickerInput<D> implements ControlValueAccessor, OnDestroy, V
243243
private _elementRef: ElementRef<HTMLInputElement>,
244244
@Optional() public _dateAdapter: DateAdapter<D>,
245245
@Optional() @Inject(MAT_DATE_FORMATS) private _dateFormats: MatDateFormats,
246-
@Optional() private _formField: MatFormField) {
246+
@Optional() @Inject(MAT_FORM_FIELD) private _formField: MatFormField) {
247247
if (!this._dateAdapter) {
248248
throw createMissingDateImplError('DateAdapter');
249249
}

src/material/form-field/form-field.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,12 @@ export interface MatFormFieldDefaultOptions {
101101
export const MAT_FORM_FIELD_DEFAULT_OPTIONS =
102102
new InjectionToken<MatFormFieldDefaultOptions>('MAT_FORM_FIELD_DEFAULT_OPTIONS');
103103

104+
/**
105+
* Injection token that can be used to inject an instances of `MatFormField`. It serves
106+
* as alternative token to the actual `MatFormField` class which would cause unnecessary
107+
* retention of the `MatFormField` class and its component metadata.
108+
*/
109+
export const MAT_FORM_FIELD = new InjectionToken<MatFormField>('MatFormField');
104110

105111
/** Container for form controls that applies Material Design styling and behavior. */
106112
@Component({
@@ -147,6 +153,9 @@ export const MAT_FORM_FIELD_DEFAULT_OPTIONS =
147153
inputs: ['color'],
148154
encapsulation: ViewEncapsulation.None,
149155
changeDetection: ChangeDetectionStrategy.OnPush,
156+
providers: [
157+
{provide: MAT_FORM_FIELD, useExisting: MatFormField},
158+
]
150159
})
151160

152161
export class MatFormField extends _MatFormFieldMixinBase

src/material/select/select.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ import {
8484
mixinErrorState,
8585
mixinTabIndex,
8686
} from '@angular/material/core';
87-
import {MatFormField, MatFormFieldControl} from '@angular/material/form-field';
87+
import {MAT_FORM_FIELD, MatFormField, MatFormFieldControl} from '@angular/material/form-field';
8888
import {defer, merge, Observable, Subject} from 'rxjs';
8989
import {
9090
distinctUntilChanged,
@@ -515,7 +515,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
515515
@Optional() private _dir: Directionality,
516516
@Optional() _parentForm: NgForm,
517517
@Optional() _parentFormGroup: FormGroupDirective,
518-
@Optional() private _parentFormField: MatFormField,
518+
@Optional() @Inject(MAT_FORM_FIELD) private _parentFormField: MatFormField,
519519
@Self() @Optional() public ngControl: NgControl,
520520
@Attribute('tabindex') tabIndex: string,
521521
@Inject(MAT_SELECT_SCROLL_STRATEGY) scrollStrategyFactory: any,

tools/public_api_guard/material/form-field.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ export declare function getMatFormFieldMissingControlError(): Error;
66

77
export declare function getMatFormFieldPlaceholderConflictError(): Error;
88

9+
export declare const MAT_FORM_FIELD: InjectionToken<MatFormField>;
10+
911
export declare const MAT_FORM_FIELD_DEFAULT_OPTIONS: InjectionToken<MatFormFieldDefaultOptions>;
1012

1113
export declare class MatError {

0 commit comments

Comments
 (0)