diff --git a/src/material/autocomplete/autocomplete.spec.ts b/src/material/autocomplete/autocomplete.spec.ts
index c5e6e7efe864..c13393f7d6e0 100644
--- a/src/material/autocomplete/autocomplete.spec.ts
+++ b/src/material/autocomplete/autocomplete.spec.ts
@@ -2496,6 +2496,34 @@ describe('MatAutocomplete', () => {
expect(event.option.value).toBe('Puerto Rico');
}));
+ it('should emit an event when an option is activated', fakeAsync(() => {
+ const fixture = createComponent(AutocompleteWithActivatedEvent);
+
+ fixture.detectChanges();
+ fixture.componentInstance.trigger.openPanel();
+ zone.simulateZoneExit();
+ fixture.detectChanges();
+
+ const input = fixture.nativeElement.querySelector('input');
+ const spy = fixture.componentInstance.optionActivated;
+ const autocomplete = fixture.componentInstance.autocomplete;
+ const options = fixture.componentInstance.options.toArray();
+
+ expect(spy).not.toHaveBeenCalled();
+
+ dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW);
+ fixture.detectChanges();
+ expect(spy.calls.mostRecent().args[0]).toEqual({source: autocomplete, option: options[0]});
+
+ dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW);
+ fixture.detectChanges();
+ expect(spy.calls.mostRecent().args[0]).toEqual({source: autocomplete, option: options[1]});
+
+ dispatchKeyboardEvent(input, 'keydown', DOWN_ARROW);
+ fixture.detectChanges();
+ expect(spy.calls.mostRecent().args[0]).toEqual({source: autocomplete, option: options[2]});
+ }));
+
it('should be able to set a custom panel connection element', () => {
const fixture = createComponent(AutocompleteWithDifferentOrigin);
@@ -2978,3 +3006,24 @@ class AutocompleteWithNativeAutocompleteAttribute {
})
class InputWithoutAutocompleteAndDisabled {
}
+
+
+@Component({
+ template: `
+
+
+
+
+
+ {{ state }}
+
+ `
+})
+class AutocompleteWithActivatedEvent {
+ states = ['California', 'West Virginia', 'Florida'];
+ optionActivated = jasmine.createSpy('optionActivated callback');
+
+ @ViewChild(MatAutocompleteTrigger) trigger: MatAutocompleteTrigger;
+ @ViewChild(MatAutocomplete) autocomplete: MatAutocomplete;
+ @ViewChildren(MatOption) options: QueryList;
+}
diff --git a/src/material/autocomplete/autocomplete.ts b/src/material/autocomplete/autocomplete.ts
index 4e96f737c907..87e519dc2e62 100644
--- a/src/material/autocomplete/autocomplete.ts
+++ b/src/material/autocomplete/autocomplete.ts
@@ -24,6 +24,7 @@ import {
TemplateRef,
ViewChild,
ViewEncapsulation,
+ OnDestroy,
} from '@angular/core';
import {
CanDisableRipple,
@@ -33,6 +34,7 @@ import {
MatOption,
mixinDisableRipple,
} from '@angular/material/core';
+import {Subscription} from 'rxjs';
/**
@@ -50,6 +52,14 @@ export class MatAutocompleteSelectedEvent {
public option: MatOption) { }
}
+/** Event object that is emitted when an autocomplete option is activated. */
+export interface MatAutocompleteActivatedEvent {
+ /** Reference to the autocomplete panel that emitted the event. */
+ source: MatAutocomplete;
+
+ /** Option that was selected. */
+ option: MatOption|null;
+}
// Boilerplate for applying mixins to MatAutocomplete.
/** @docs-private */
@@ -91,7 +101,8 @@ export function MAT_AUTOCOMPLETE_DEFAULT_OPTIONS_FACTORY(): MatAutocompleteDefau
]
})
export class MatAutocomplete extends _MatAutocompleteMixinBase implements AfterContentInit,
- CanDisableRipple {
+ CanDisableRipple, OnDestroy {
+ private _activeOptionChanges = Subscription.EMPTY;
/** Manages active item in option list based on key events. */
_keyManager: ActiveDescendantKeyManager;
@@ -149,6 +160,10 @@ export class MatAutocomplete extends _MatAutocompleteMixinBase implements AfterC
/** Event that is emitted when the autocomplete panel is closed. */
@Output() readonly closed: EventEmitter = new EventEmitter();
+ /** Emits whenever an option is activated using the keyboard. */
+ @Output() readonly optionActivated: EventEmitter =
+ new EventEmitter();
+
/**
* Takes classes set on the host mat-autocomplete element and applies them to the panel
* inside the overlay container to allow for easy styling.
@@ -183,10 +198,18 @@ export class MatAutocomplete extends _MatAutocompleteMixinBase implements AfterC
ngAfterContentInit() {
this._keyManager = new ActiveDescendantKeyManager(this.options).withWrap();
+ this._activeOptionChanges = this._keyManager.change.subscribe(index => {
+ this.optionActivated.emit({source: this, option: this.options.toArray()[index] || null});
+ });
+
// Set the initial visibility state.
this._setVisibility();
}
+ ngOnDestroy() {
+ this._activeOptionChanges.unsubscribe();
+ }
+
/**
* Sets the panel scrollTop. This allows us to manually scroll to display options
* above or below the fold, as they are not actually being focused when active.
diff --git a/tools/public_api_guard/material/autocomplete.d.ts b/tools/public_api_guard/material/autocomplete.d.ts
index 52719b4d4280..fe958ac72a5b 100644
--- a/tools/public_api_guard/material/autocomplete.d.ts
+++ b/tools/public_api_guard/material/autocomplete.d.ts
@@ -20,7 +20,7 @@ export declare const MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY_PROVIDER: {
export declare const MAT_AUTOCOMPLETE_VALUE_ACCESSOR: any;
-export declare class MatAutocomplete extends _MatAutocompleteMixinBase implements AfterContentInit, CanDisableRipple {
+export declare class MatAutocomplete extends _MatAutocompleteMixinBase implements AfterContentInit, CanDisableRipple, OnDestroy {
_classList: {
[key: string]: boolean;
};
@@ -34,6 +34,7 @@ export declare class MatAutocomplete extends _MatAutocompleteMixinBase implement
id: string;
get isOpen(): boolean;
readonly opened: EventEmitter;
+ readonly optionActivated: EventEmitter;
optionGroups: QueryList;
readonly optionSelected: EventEmitter;
options: QueryList;
@@ -47,12 +48,18 @@ export declare class MatAutocomplete extends _MatAutocompleteMixinBase implement
_setScrollTop(scrollTop: number): void;
_setVisibility(): void;
ngAfterContentInit(): void;
+ ngOnDestroy(): void;
static ngAcceptInputType_autoActiveFirstOption: BooleanInput;
static ngAcceptInputType_disableRipple: BooleanInput;
- static ɵcmp: i0.ɵɵComponentDefWithMeta;
+ static ɵcmp: i0.ɵɵComponentDefWithMeta;
static ɵfac: i0.ɵɵFactoryDef;
}
+export interface MatAutocompleteActivatedEvent {
+ option: MatOption | null;
+ source: MatAutocomplete;
+}
+
export interface MatAutocompleteDefaultOptions {
autoActiveFirstOption?: boolean;
}