diff --git a/src/lib/autocomplete/BUILD.bazel b/src/lib/autocomplete/BUILD.bazel
index 6fe3521b2b2..4d1f2486b75 100644
--- a/src/lib/autocomplete/BUILD.bazel
+++ b/src/lib/autocomplete/BUILD.bazel
@@ -17,6 +17,7 @@ ng_module(
"//src/cdk/keycodes",
"//src/cdk/portal",
"//src/cdk/overlay",
+ "//src/cdk/coercion",
],
tsconfig = "//src/lib:tsconfig-build.json",
)
diff --git a/src/lib/autocomplete/autocomplete-trigger.ts b/src/lib/autocomplete/autocomplete-trigger.ts
index 541d520653c..ca254dd6abf 100644
--- a/src/lib/autocomplete/autocomplete-trigger.ts
+++ b/src/lib/autocomplete/autocomplete-trigger.ts
@@ -44,6 +44,7 @@ import {
import {MatFormField} from '@angular/material/form-field';
import {Subscription, defer, fromEvent, merge, of as observableOf, Subject, Observable} from 'rxjs';
import {MatAutocomplete} from './autocomplete';
+import {coerceBooleanProperty} from '@angular/cdk/coercion';
/**
@@ -93,12 +94,12 @@ export function getMatAutocompleteMissingPanelError(): Error {
@Directive({
selector: `input[matAutocomplete], textarea[matAutocomplete]`,
host: {
- 'role': 'combobox',
'autocomplete': 'off',
- 'aria-autocomplete': 'list',
+ '[attr.role]': 'autocompleteDisabled ? null : "combobox"',
+ '[attr.aria-autocomplete]': 'autocompleteDisabled ? null : "list"',
'[attr.aria-activedescendant]': 'activeOption?.id',
- '[attr.aria-expanded]': 'panelOpen.toString()',
- '[attr.aria-owns]': 'autocomplete?.id',
+ '[attr.aria-expanded]': 'autocompleteDisabled ? null : panelOpen.toString()',
+ '[attr.aria-owns]': 'autocompleteDisabled ? null : autocomplete?.id',
// Note: we use `focusin`, as opposed to `focus`, in order to open the panel
// a little earlier. This avoids issues where IE delays the focusing of the input.
'(focusin)': '_handleFocus()',
@@ -113,6 +114,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
private _overlayRef: OverlayRef | null;
private _portal: TemplatePortal;
private _componentDestroyed = false;
+ private _autocompleteDisabled = false;
/** Old value of the native input. Used to work around issues with the `input` event on IE. */
private _previousValue: string | number | null;
@@ -141,6 +143,16 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
/** The autocomplete panel to be attached to this trigger. */
@Input('matAutocomplete') autocomplete: MatAutocomplete;
+ /**
+ * Whether the autocomplete is disabled. When disabled, the element will
+ * act as a regular input and the user won't be able to open the panel.
+ */
+ @Input('matAutocompleteDisabled')
+ get autocompleteDisabled(): boolean { return this._autocompleteDisabled; }
+ set autocompleteDisabled(value: boolean) {
+ this._autocompleteDisabled = coerceBooleanProperty(value);
+ }
+
constructor(private _element: ElementRef, private _overlay: Overlay,
private _viewContainerRef: ViewContainerRef,
private _zone: NgZone,
@@ -569,7 +581,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
/** Determines whether the panel can be opened. */
private _canOpen(): boolean {
const element: HTMLInputElement = this._element.nativeElement;
- return !element.readOnly && !element.disabled;
+ return !element.readOnly && !element.disabled && !this._autocompleteDisabled;
}
}
diff --git a/src/lib/autocomplete/autocomplete.spec.ts b/src/lib/autocomplete/autocomplete.spec.ts
index 4b4e9be5d8e..a9b6331fcf0 100644
--- a/src/lib/autocomplete/autocomplete.spec.ts
+++ b/src/lib/autocomplete/autocomplete.spec.ts
@@ -455,6 +455,20 @@ describe('MatAutocomplete', () => {
expect(fixture.componentInstance.closedSpy).not.toHaveBeenCalled();
});
+ it('should not be able to open the panel if the autocomplete is disabled', () => {
+ expect(fixture.componentInstance.trigger.panelOpen)
+ .toBe(false, `Expected panel state to start out closed.`);
+
+ fixture.componentInstance.autocompleteDisabled = true;
+ fixture.detectChanges();
+
+ dispatchFakeEvent(input, 'focusin');
+ fixture.detectChanges();
+
+ expect(fixture.componentInstance.trigger.panelOpen)
+ .toBe(false, `Expected panel to remain closed.`);
+ });
+
});
it('should have the correct text direction in RTL', () => {
@@ -1300,6 +1314,16 @@ describe('MatAutocomplete', () => {
expect(document.activeElement).toBe(input, 'Expected focus to be restored to the input.');
}));
+ it('should remove autocomplete-specific aria attributes when autocomplete is disabled', () => {
+ fixture.componentInstance.autocompleteDisabled = true;
+ fixture.detectChanges();
+
+ expect(input.getAttribute('role')).toBeFalsy();
+ expect(input.getAttribute('aria-autocomplete')).toBeFalsy();
+ expect(input.getAttribute('aria-expanded')).toBeFalsy();
+ expect(input.getAttribute('aria-owns')).toBeFalsy();
+ });
+
});
describe('Fallback positions', () => {
@@ -1959,7 +1983,12 @@ describe('MatAutocomplete', () => {
@Component({
template: `
-
+