Skip to content

Commit 925f235

Browse files
committed
refactor(material/autocomplete): remove mixin class usages
Replaces mixin class usages in the autocomplete with input transforms.
1 parent f8fccef commit 925f235

File tree

3 files changed

+41
-71
lines changed

3 files changed

+41
-71
lines changed

src/material/autocomplete/autocomplete-trigger.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import {addAriaReferencedId, removeAriaReferencedId} from '@angular/cdk/a11y';
1010
import {
1111
AfterViewInit,
12+
booleanAttribute,
1213
ChangeDetectorRef,
1314
Directive,
1415
ElementRef,
@@ -26,7 +27,6 @@ import {
2627
} from '@angular/core';
2728
import {DOCUMENT} from '@angular/common';
2829
import {Directionality} from '@angular/cdk/bidi';
29-
import {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion';
3030
import {DOWN_ARROW, ENTER, ESCAPE, TAB, UP_ARROW, hasModifierKey} from '@angular/cdk/keycodes';
3131
import {_getEventTarget} from '@angular/cdk/platform';
3232
import {TemplatePortal} from '@angular/cdk/portal';
@@ -125,7 +125,6 @@ export class MatAutocompleteTrigger
125125
private _overlayRef: OverlayRef | null;
126126
private _portal: TemplatePortal;
127127
private _componentDestroyed = false;
128-
private _autocompleteDisabled = false;
129128
private _scrollStrategy: () => ScrollStrategy;
130129
private _keydownSubscription: Subscription | null;
131130
private _outsideClickSubscription: Subscription | null;
@@ -213,13 +212,8 @@ export class MatAutocompleteTrigger
213212
* Whether the autocomplete is disabled. When disabled, the element will
214213
* act as a regular input and the user won't be able to open the panel.
215214
*/
216-
@Input('matAutocompleteDisabled')
217-
get autocompleteDisabled(): boolean {
218-
return this._autocompleteDisabled;
219-
}
220-
set autocompleteDisabled(value: BooleanInput) {
221-
this._autocompleteDisabled = coerceBooleanProperty(value);
222-
}
215+
@Input({alias: 'matAutocompleteDisabled', transform: booleanAttribute})
216+
autocompleteDisabled: boolean;
223217

224218
constructor(
225219
private _element: ElementRef<HTMLInputElement>,
@@ -897,7 +891,7 @@ export class MatAutocompleteTrigger
897891
/** Determines whether the panel can be opened. */
898892
private _canOpen(): boolean {
899893
const element = this._element.nativeElement;
900-
return !element.readOnly && !element.disabled && !this._autocompleteDisabled;
894+
return !element.readOnly && !element.disabled && !this.autocompleteDisabled;
901895
}
902896

903897
/** Use defaultView of injected document if available or fallback to global window reference */

src/material/autocomplete/autocomplete.ts

Lines changed: 17 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,18 @@ import {
2323
TemplateRef,
2424
ViewChild,
2525
ViewEncapsulation,
26+
booleanAttribute,
2627
} from '@angular/core';
2728
import {AnimationEvent} from '@angular/animations';
2829
import {
2930
MAT_OPTGROUP,
3031
MAT_OPTION_PARENT_COMPONENT,
3132
MatOptgroup,
3233
MatOption,
33-
mixinDisableRipple,
34-
CanDisableRipple,
3534
ThemePalette,
3635
} from '@angular/material/core';
3736
import {ActiveDescendantKeyManager} from '@angular/cdk/a11y';
38-
import {BooleanInput, coerceBooleanProperty, coerceStringArray} from '@angular/cdk/coercion';
37+
import {coerceStringArray} from '@angular/cdk/coercion';
3938
import {Platform} from '@angular/cdk/platform';
4039
import {panelAnimation} from './animations';
4140
import {Subscription} from 'rxjs';
@@ -65,10 +64,6 @@ export interface MatAutocompleteActivatedEvent {
6564
option: MatOption | null;
6665
}
6766

68-
// Boilerplate for applying mixins to MatAutocomplete.
69-
/** @docs-private */
70-
const _MatAutocompleteMixinBase = mixinDisableRipple(class {});
71-
7267
/** Default `mat-autocomplete` options that can be overridden. */
7368
export interface MatAutocompleteDefaultOptions {
7469
/** Whether the first option should be highlighted when an autocomplete panel is opened. */
@@ -117,18 +112,14 @@ export function MAT_AUTOCOMPLETE_DEFAULT_OPTIONS_FACTORY(): MatAutocompleteDefau
117112
encapsulation: ViewEncapsulation.None,
118113
changeDetection: ChangeDetectionStrategy.OnPush,
119114
exportAs: 'matAutocomplete',
120-
inputs: ['disableRipple'],
121115
host: {
122116
'class': 'mat-mdc-autocomplete',
123117
'ngSkipHydration': '',
124118
},
125119
providers: [{provide: MAT_OPTION_PARENT_COMPONENT, useExisting: MatAutocomplete}],
126120
animations: [panelAnimation],
127121
})
128-
export class MatAutocomplete
129-
extends _MatAutocompleteMixinBase
130-
implements AfterContentInit, CanDisableRipple, OnDestroy
131-
{
122+
export class MatAutocomplete implements AfterContentInit, OnDestroy {
132123
private _activeOptionChanges = Subscription.EMPTY;
133124

134125
/** Class to apply to the panel when it's visible. */
@@ -189,46 +180,28 @@ export class MatAutocomplete
189180
* Whether the first option should be highlighted when the autocomplete panel is opened.
190181
* Can be configured globally through the `MAT_AUTOCOMPLETE_DEFAULT_OPTIONS` token.
191182
*/
192-
@Input()
193-
get autoActiveFirstOption(): boolean {
194-
return this._autoActiveFirstOption;
195-
}
196-
set autoActiveFirstOption(value: BooleanInput) {
197-
this._autoActiveFirstOption = coerceBooleanProperty(value);
198-
}
199-
private _autoActiveFirstOption: boolean;
183+
@Input({transform: booleanAttribute}) autoActiveFirstOption: boolean;
200184

201185
/** Whether the active option should be selected as the user is navigating. */
202-
@Input()
203-
get autoSelectActiveOption(): boolean {
204-
return this._autoSelectActiveOption;
205-
}
206-
set autoSelectActiveOption(value: BooleanInput) {
207-
this._autoSelectActiveOption = coerceBooleanProperty(value);
208-
}
209-
private _autoSelectActiveOption: boolean;
186+
@Input({transform: booleanAttribute}) autoSelectActiveOption: boolean;
210187

211188
/**
212189
* Whether the user is required to make a selection when they're interacting with the
213190
* autocomplete. If the user moves away from the autocomplete without selecting an option from
214191
* the list, the value will be reset. If the user opens the panel and closes it without
215192
* interacting or selecting a value, the initial value will be kept.
216193
*/
217-
@Input()
218-
get requireSelection(): boolean {
219-
return this._requireSelection;
220-
}
221-
set requireSelection(value: BooleanInput) {
222-
this._requireSelection = coerceBooleanProperty(value);
223-
}
224-
private _requireSelection: boolean;
194+
@Input({transform: booleanAttribute}) requireSelection: boolean;
225195

226196
/**
227197
* Specify the width of the autocomplete panel. Can be any CSS sizing value, otherwise it will
228198
* match the width of its host.
229199
*/
230200
@Input() panelWidth: string | number;
231201

202+
/** Whether ripples are disabled within the autocomplete panel. */
203+
@Input({transform: booleanAttribute}) disableRipple: boolean;
204+
232205
/** Event that is emitted whenever an option from the list is selected. */
233206
@Output() readonly optionSelected: EventEmitter<MatAutocompleteSelectedEvent> =
234207
new EventEmitter<MatAutocompleteSelectedEvent>();
@@ -268,16 +241,15 @@ export class MatAutocomplete
268241
_classList: {[key: string]: boolean} = {};
269242

270243
/** Whether checkmark indicator for single-selection options is hidden. */
271-
@Input()
244+
@Input({transform: booleanAttribute})
272245
get hideSingleSelectionIndicator(): boolean {
273246
return this._hideSingleSelectionIndicator;
274247
}
275-
set hideSingleSelectionIndicator(value: BooleanInput) {
276-
this._hideSingleSelectionIndicator = coerceBooleanProperty(value);
248+
set hideSingleSelectionIndicator(value: boolean) {
249+
this._hideSingleSelectionIndicator = value;
277250
this._syncParentProperties();
278251
}
279-
private _hideSingleSelectionIndicator: boolean =
280-
this._defaults.hideSingleSelectionIndicator ?? false;
252+
private _hideSingleSelectionIndicator: boolean;
281253

282254
/** Syncs the parent state with the individual options. */
283255
_syncParentProperties(): void {
@@ -303,16 +275,15 @@ export class MatAutocomplete
303275
@Inject(MAT_AUTOCOMPLETE_DEFAULT_OPTIONS) protected _defaults: MatAutocompleteDefaultOptions,
304276
platform?: Platform,
305277
) {
306-
super();
307-
308278
// TODO(crisbeto): the problem that the `inertGroups` option resolves is only present on
309279
// Safari using VoiceOver. We should occasionally check back to see whether the bug
310280
// wasn't resolved in VoiceOver, and if it has, we can remove this and the `inertGroups`
311281
// option altogether.
312282
this.inertGroups = platform?.SAFARI || false;
313-
this._autoActiveFirstOption = !!_defaults.autoActiveFirstOption;
314-
this._autoSelectActiveOption = !!_defaults.autoSelectActiveOption;
315-
this._requireSelection = !!_defaults.requireSelection;
283+
this.autoActiveFirstOption = !!_defaults.autoActiveFirstOption;
284+
this.autoSelectActiveOption = !!_defaults.autoSelectActiveOption;
285+
this.requireSelection = !!_defaults.requireSelection;
286+
this._hideSingleSelectionIndicator = this._defaults.hideSingleSelectionIndicator ?? false;
316287
}
317288

318289
ngAfterContentInit() {

tools/public_api_guard/material/autocomplete.md

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,11 @@
44
55
```ts
66

7-
import { _AbstractConstructor } from '@angular/material/core';
87
import { ActiveDescendantKeyManager } from '@angular/cdk/a11y';
98
import { AfterContentInit } from '@angular/core';
109
import { AfterViewInit } from '@angular/core';
1110
import { AnimationEvent as AnimationEvent_2 } from '@angular/animations';
12-
import { BooleanInput } from '@angular/cdk/coercion';
13-
import { CanDisableRipple } from '@angular/material/core';
1411
import { ChangeDetectorRef } from '@angular/core';
15-
import { _Constructor } from '@angular/material/core';
1612
import { ControlValueAccessor } from '@angular/forms';
1713
import { Directionality } from '@angular/cdk/bidi';
1814
import { ElementRef } from '@angular/core';
@@ -67,15 +63,13 @@ export const MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY_PROVIDER: {
6763
export const MAT_AUTOCOMPLETE_VALUE_ACCESSOR: any;
6864

6965
// @public
70-
export class MatAutocomplete extends _MatAutocompleteMixinBase implements AfterContentInit, CanDisableRipple, OnDestroy {
66+
export class MatAutocomplete implements AfterContentInit, OnDestroy {
7167
constructor(_changeDetectorRef: ChangeDetectorRef, _elementRef: ElementRef<HTMLElement>, _defaults: MatAutocompleteDefaultOptions, platform?: Platform);
7268
_animationDone: EventEmitter<AnimationEvent_2>;
7369
ariaLabel: string;
7470
ariaLabelledby: string;
75-
get autoActiveFirstOption(): boolean;
76-
set autoActiveFirstOption(value: BooleanInput);
77-
get autoSelectActiveOption(): boolean;
78-
set autoSelectActiveOption(value: BooleanInput);
71+
autoActiveFirstOption: boolean;
72+
autoSelectActiveOption: boolean;
7973
set classList(value: string | string[]);
8074
// (undocumented)
8175
_classList: {
@@ -84,19 +78,30 @@ export class MatAutocomplete extends _MatAutocompleteMixinBase implements AfterC
8478
readonly closed: EventEmitter<void>;
8579
// (undocumented)
8680
protected _defaults: MatAutocompleteDefaultOptions;
81+
disableRipple: boolean;
8782
displayWith: ((value: any) => string) | null;
8883
_emitSelectEvent(option: MatOption): void;
8984
_getPanelAriaLabelledby(labelId: string | null): string | null;
9085
_getScrollTop(): number;
9186
get hideSingleSelectionIndicator(): boolean;
92-
set hideSingleSelectionIndicator(value: BooleanInput);
87+
set hideSingleSelectionIndicator(value: boolean);
9388
id: string;
9489
readonly inertGroups: boolean;
9590
get isOpen(): boolean;
9691
// (undocumented)
9792
_isOpen: boolean;
9893
_keyManager: ActiveDescendantKeyManager<MatOption>;
9994
// (undocumented)
95+
static ngAcceptInputType_autoActiveFirstOption: unknown;
96+
// (undocumented)
97+
static ngAcceptInputType_autoSelectActiveOption: unknown;
98+
// (undocumented)
99+
static ngAcceptInputType_disableRipple: unknown;
100+
// (undocumented)
101+
static ngAcceptInputType_hideSingleSelectionIndicator: unknown;
102+
// (undocumented)
103+
static ngAcceptInputType_requireSelection: unknown;
104+
// (undocumented)
100105
ngAfterContentInit(): void;
101106
// (undocumented)
102107
ngOnDestroy(): void;
@@ -107,8 +112,7 @@ export class MatAutocomplete extends _MatAutocompleteMixinBase implements AfterC
107112
readonly optionSelected: EventEmitter<MatAutocompleteSelectedEvent>;
108113
panel: ElementRef;
109114
panelWidth: string | number;
110-
get requireSelection(): boolean;
111-
set requireSelection(value: BooleanInput);
115+
requireSelection: boolean;
112116
_setColor(value: ThemePalette): void;
113117
_setScrollTop(scrollTop: number): void;
114118
_setVisibility(): void;
@@ -118,7 +122,7 @@ export class MatAutocomplete extends _MatAutocompleteMixinBase implements AfterC
118122
_syncParentProperties(): void;
119123
template: TemplateRef<any>;
120124
// (undocumented)
121-
static ɵcmp: i0.ɵɵComponentDeclaration<MatAutocomplete, "mat-autocomplete", ["matAutocomplete"], { "disableRipple": { "alias": "disableRipple"; "required": false; }; "ariaLabel": { "alias": "aria-label"; "required": false; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; }; "displayWith": { "alias": "displayWith"; "required": false; }; "autoActiveFirstOption": { "alias": "autoActiveFirstOption"; "required": false; }; "autoSelectActiveOption": { "alias": "autoSelectActiveOption"; "required": false; }; "requireSelection": { "alias": "requireSelection"; "required": false; }; "panelWidth": { "alias": "panelWidth"; "required": false; }; "classList": { "alias": "class"; "required": false; }; "hideSingleSelectionIndicator": { "alias": "hideSingleSelectionIndicator"; "required": false; }; }, { "optionSelected": "optionSelected"; "opened": "opened"; "closed": "closed"; "optionActivated": "optionActivated"; }, ["options", "optionGroups"], ["*"], false, never>;
125+
static ɵcmp: i0.ɵɵComponentDeclaration<MatAutocomplete, "mat-autocomplete", ["matAutocomplete"], { "ariaLabel": { "alias": "aria-label"; "required": false; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; }; "displayWith": { "alias": "displayWith"; "required": false; }; "autoActiveFirstOption": { "alias": "autoActiveFirstOption"; "required": false; }; "autoSelectActiveOption": { "alias": "autoSelectActiveOption"; "required": false; }; "requireSelection": { "alias": "requireSelection"; "required": false; }; "panelWidth": { "alias": "panelWidth"; "required": false; }; "disableRipple": { "alias": "disableRipple"; "required": false; }; "classList": { "alias": "class"; "required": false; }; "hideSingleSelectionIndicator": { "alias": "hideSingleSelectionIndicator"; "required": false; }; }, { "optionSelected": "optionSelected"; "opened": "opened"; "closed": "closed"; "optionActivated": "optionActivated"; }, ["options", "optionGroups"], ["*"], false, never>;
122126
// (undocumented)
123127
static ɵfac: i0.ɵɵFactoryDeclaration<MatAutocomplete, never>;
124128
}
@@ -174,8 +178,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, AfterViewIn
174178
get activeOption(): MatOption | null;
175179
autocomplete: MatAutocomplete;
176180
autocompleteAttribute: string;
177-
get autocompleteDisabled(): boolean;
178-
set autocompleteDisabled(value: BooleanInput);
181+
autocompleteDisabled: boolean;
179182
closePanel(): void;
180183
connectedTo: MatAutocompleteOrigin;
181184
// (undocumented)
@@ -187,6 +190,8 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, AfterViewIn
187190
// (undocumented)
188191
_handleKeydown(event: KeyboardEvent): void;
189192
// (undocumented)
193+
static ngAcceptInputType_autocompleteDisabled: unknown;
194+
// (undocumented)
190195
ngAfterViewInit(): void;
191196
// (undocumented)
192197
ngOnChanges(changes: SimpleChanges): void;

0 commit comments

Comments
 (0)