Skip to content

Commit e8bc0e9

Browse files
crisbetojosephperrott
authored andcommitted
feat(autocomplete): allow autocomplete panel to be disabled (#11142)
1 parent ab1204d commit e8bc0e9

File tree

3 files changed

+49
-6
lines changed

3 files changed

+49
-6
lines changed

src/lib/autocomplete/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ ng_module(
1717
"//src/cdk/keycodes",
1818
"//src/cdk/portal",
1919
"//src/cdk/overlay",
20+
"//src/cdk/coercion",
2021
],
2122
tsconfig = "//src/lib:tsconfig-build.json",
2223
)

src/lib/autocomplete/autocomplete-trigger.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import {
4444
import {MatFormField} from '@angular/material/form-field';
4545
import {Subscription, defer, fromEvent, merge, of as observableOf, Subject, Observable} from 'rxjs';
4646
import {MatAutocomplete} from './autocomplete';
47+
import {coerceBooleanProperty} from '@angular/cdk/coercion';
4748

4849

4950
/**
@@ -93,12 +94,12 @@ export function getMatAutocompleteMissingPanelError(): Error {
9394
@Directive({
9495
selector: `input[matAutocomplete], textarea[matAutocomplete]`,
9596
host: {
96-
'role': 'combobox',
9797
'autocomplete': 'off',
98-
'aria-autocomplete': 'list',
98+
'[attr.role]': 'autocompleteDisabled ? null : "combobox"',
99+
'[attr.aria-autocomplete]': 'autocompleteDisabled ? null : "list"',
99100
'[attr.aria-activedescendant]': 'activeOption?.id',
100-
'[attr.aria-expanded]': 'panelOpen.toString()',
101-
'[attr.aria-owns]': 'autocomplete?.id',
101+
'[attr.aria-expanded]': 'autocompleteDisabled ? null : panelOpen.toString()',
102+
'[attr.aria-owns]': 'autocompleteDisabled ? null : autocomplete?.id',
102103
// Note: we use `focusin`, as opposed to `focus`, in order to open the panel
103104
// a little earlier. This avoids issues where IE delays the focusing of the input.
104105
'(focusin)': '_handleFocus()',
@@ -113,6 +114,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
113114
private _overlayRef: OverlayRef | null;
114115
private _portal: TemplatePortal;
115116
private _componentDestroyed = false;
117+
private _autocompleteDisabled = false;
116118

117119
/** Old value of the native input. Used to work around issues with the `input` event on IE. */
118120
private _previousValue: string | number | null;
@@ -141,6 +143,16 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
141143
/** The autocomplete panel to be attached to this trigger. */
142144
@Input('matAutocomplete') autocomplete: MatAutocomplete;
143145

146+
/**
147+
* Whether the autocomplete is disabled. When disabled, the element will
148+
* act as a regular input and the user won't be able to open the panel.
149+
*/
150+
@Input('matAutocompleteDisabled')
151+
get autocompleteDisabled(): boolean { return this._autocompleteDisabled; }
152+
set autocompleteDisabled(value: boolean) {
153+
this._autocompleteDisabled = coerceBooleanProperty(value);
154+
}
155+
144156
constructor(private _element: ElementRef, private _overlay: Overlay,
145157
private _viewContainerRef: ViewContainerRef,
146158
private _zone: NgZone,
@@ -569,7 +581,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
569581
/** Determines whether the panel can be opened. */
570582
private _canOpen(): boolean {
571583
const element: HTMLInputElement = this._element.nativeElement;
572-
return !element.readOnly && !element.disabled;
584+
return !element.readOnly && !element.disabled && !this._autocompleteDisabled;
573585
}
574586

575587
}

src/lib/autocomplete/autocomplete.spec.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,20 @@ describe('MatAutocomplete', () => {
455455
expect(fixture.componentInstance.closedSpy).not.toHaveBeenCalled();
456456
});
457457

458+
it('should not be able to open the panel if the autocomplete is disabled', () => {
459+
expect(fixture.componentInstance.trigger.panelOpen)
460+
.toBe(false, `Expected panel state to start out closed.`);
461+
462+
fixture.componentInstance.autocompleteDisabled = true;
463+
fixture.detectChanges();
464+
465+
dispatchFakeEvent(input, 'focusin');
466+
fixture.detectChanges();
467+
468+
expect(fixture.componentInstance.trigger.panelOpen)
469+
.toBe(false, `Expected panel to remain closed.`);
470+
});
471+
458472
});
459473

460474
it('should have the correct text direction in RTL', () => {
@@ -1300,6 +1314,16 @@ describe('MatAutocomplete', () => {
13001314
expect(document.activeElement).toBe(input, 'Expected focus to be restored to the input.');
13011315
}));
13021316

1317+
it('should remove autocomplete-specific aria attributes when autocomplete is disabled', () => {
1318+
fixture.componentInstance.autocompleteDisabled = true;
1319+
fixture.detectChanges();
1320+
1321+
expect(input.getAttribute('role')).toBeFalsy();
1322+
expect(input.getAttribute('aria-autocomplete')).toBeFalsy();
1323+
expect(input.getAttribute('aria-expanded')).toBeFalsy();
1324+
expect(input.getAttribute('aria-owns')).toBeFalsy();
1325+
});
1326+
13031327
});
13041328

13051329
describe('Fallback positions', () => {
@@ -1959,7 +1983,12 @@ describe('MatAutocomplete', () => {
19591983
@Component({
19601984
template: `
19611985
<mat-form-field [floatLabel]="floatLabel" [style.width.px]="width">
1962-
<input matInput placeholder="State" [matAutocomplete]="auto" [formControl]="stateCtrl">
1986+
<input
1987+
matInput
1988+
placeholder="State"
1989+
[matAutocomplete]="auto"
1990+
[matAutocompleteDisabled]="autocompleteDisabled"
1991+
[formControl]="stateCtrl">
19631992
</mat-form-field>
19641993
19651994
<mat-autocomplete class="class-one class-two" #auto="matAutocomplete" [displayWith]="displayFn"
@@ -1977,6 +2006,7 @@ class SimpleAutocomplete implements OnDestroy {
19772006
floatLabel = 'auto';
19782007
width: number;
19792008
disableRipple = false;
2009+
autocompleteDisabled = false;
19802010
openedSpy = jasmine.createSpy('autocomplete opened spy');
19812011
closedSpy = jasmine.createSpy('autocomplete closed spy');
19822012

0 commit comments

Comments
 (0)