mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
refactor(autocomplete): make keyboard and visibility calls synchronous (#6441)
This commit is contained in:
committed by
Kara
parent
6e3bbcb6ef
commit
36da4c3991
@@ -26,15 +26,13 @@ export class ActiveDescendantKeyManager<T> extends ListKeyManager<Highlightable
|
||||
* styles from the previously active item.
|
||||
*/
|
||||
setActiveItem(index: number): void {
|
||||
Promise.resolve().then(() => {
|
||||
if (this.activeItem) {
|
||||
this.activeItem.setInactiveStyles();
|
||||
}
|
||||
super.setActiveItem(index);
|
||||
if (this.activeItem) {
|
||||
this.activeItem.setActiveStyles();
|
||||
}
|
||||
});
|
||||
if (this.activeItem) {
|
||||
this.activeItem.setInactiveStyles();
|
||||
}
|
||||
super.setActiveItem(index);
|
||||
if (this.activeItem) {
|
||||
this.activeItem.setActiveStyles();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -550,13 +550,12 @@ describe('Key managers', () => {
|
||||
describe('ActiveDescendantKeyManager', () => {
|
||||
let keyManager: ActiveDescendantKeyManager<FakeHighlightable>;
|
||||
|
||||
beforeEach(fakeAsync(() => {
|
||||
beforeEach(() => {
|
||||
itemList.items = [new FakeHighlightable(), new FakeHighlightable(), new FakeHighlightable()];
|
||||
keyManager = new ActiveDescendantKeyManager<FakeHighlightable>(itemList);
|
||||
|
||||
// first item is already focused
|
||||
keyManager.setFirstItemActive();
|
||||
tick();
|
||||
|
||||
spyOn(itemList.items[0], 'setActiveStyles');
|
||||
spyOn(itemList.items[1], 'setActiveStyles');
|
||||
@@ -565,44 +564,38 @@ describe('Key managers', () => {
|
||||
spyOn(itemList.items[0], 'setInactiveStyles');
|
||||
spyOn(itemList.items[1], 'setInactiveStyles');
|
||||
spyOn(itemList.items[2], 'setInactiveStyles');
|
||||
}));
|
||||
});
|
||||
|
||||
it('should set subsequent items as active with the DOWN arrow', fakeAsync(() => {
|
||||
it('should set subsequent items as active with the DOWN arrow', () => {
|
||||
keyManager.onKeydown(fakeKeyEvents.downArrow);
|
||||
tick();
|
||||
|
||||
expect(itemList.items[1].setActiveStyles).toHaveBeenCalled();
|
||||
expect(itemList.items[2].setActiveStyles).not.toHaveBeenCalled();
|
||||
|
||||
keyManager.onKeydown(fakeKeyEvents.downArrow);
|
||||
tick();
|
||||
|
||||
expect(itemList.items[2].setActiveStyles).toHaveBeenCalled();
|
||||
}));
|
||||
});
|
||||
|
||||
it('should set previous items as active with the UP arrow', fakeAsync(() => {
|
||||
it('should set previous items as active with the UP arrow', () => {
|
||||
keyManager.setLastItemActive();
|
||||
tick();
|
||||
|
||||
keyManager.onKeydown(fakeKeyEvents.upArrow);
|
||||
tick();
|
||||
|
||||
expect(itemList.items[1].setActiveStyles).toHaveBeenCalled();
|
||||
expect(itemList.items[0].setActiveStyles).not.toHaveBeenCalled();
|
||||
|
||||
keyManager.onKeydown(fakeKeyEvents.upArrow);
|
||||
tick();
|
||||
expect(itemList.items[0].setActiveStyles).toHaveBeenCalled();
|
||||
}));
|
||||
|
||||
it('should set inactive styles on previously active items', fakeAsync(() => {
|
||||
expect(itemList.items[0].setActiveStyles).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should set inactive styles on previously active items', () => {
|
||||
keyManager.onKeydown(fakeKeyEvents.downArrow);
|
||||
tick();
|
||||
expect(itemList.items[0].setInactiveStyles).toHaveBeenCalled();
|
||||
|
||||
keyManager.onKeydown(fakeKeyEvents.upArrow);
|
||||
tick();
|
||||
expect(itemList.items[1].setInactiveStyles).toHaveBeenCalled();
|
||||
}));
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import {startWith as startWithOperator} from 'rxjs/operator/startWith';
|
||||
import {debounceTime as debounceTimeOperator} from 'rxjs/operator/debounceTime';
|
||||
import {auditTime as auditTimeOperator} from 'rxjs/operator/auditTime';
|
||||
import {takeUntil as takeUntilOperator} from 'rxjs/operator/takeUntil';
|
||||
import {delay as delayOperator} from 'rxjs/operator/delay';
|
||||
|
||||
/**
|
||||
* Represents a strongly-typed chain of RxJS operators.
|
||||
@@ -71,6 +72,9 @@ export interface StrictRxChain<T> {
|
||||
|
||||
call(operator: takeUntilOperatorType<T>, notifier: Observable<any>): StrictRxChain<T>;
|
||||
|
||||
call(operator: delayOperatorType<T>, delay: number | Date, scheduler?: IScheduler):
|
||||
StrictRxChain<T>;
|
||||
|
||||
subscribe(fn: (t: T) => void): Subscription;
|
||||
|
||||
result(): Observable<T>;
|
||||
@@ -89,6 +93,7 @@ export class StartWithBrand { private _; }
|
||||
export class DebounceTimeBrand { private _; }
|
||||
export class AuditTimeBrand { private _; }
|
||||
export class TakeUntilBrand { private _; }
|
||||
export class DelayBrand { private _; }
|
||||
/* tslint:enable:no-unused-variable */
|
||||
|
||||
|
||||
@@ -104,6 +109,7 @@ export type startWithOperatorType<T> = typeof startWithOperator & StartWithBrand
|
||||
export type debounceTimeOperatorType<T> = typeof debounceTimeOperator & DebounceTimeBrand;
|
||||
export type auditTimeOperatorType<T> = typeof auditTimeOperator & AuditTimeBrand;
|
||||
export type takeUntilOperatorType<T> = typeof takeUntilOperator & TakeUntilBrand;
|
||||
export type delayOperatorType<T> = typeof delayOperator & DelayBrand;
|
||||
|
||||
// We add `Function` to the type intersection to make this nomically different from
|
||||
// `finallyOperatorType` while still being structurally the same. Without this, TypeScript tries to
|
||||
@@ -123,3 +129,4 @@ export const debounceTime =
|
||||
debounceTimeOperator as typeof debounceTimeOperator & DebounceTimeBrand & Function;
|
||||
export const auditTime = auditTimeOperator as typeof auditTimeOperator & AuditTimeBrand & Function;
|
||||
export const takeUntil = takeUntilOperator as typeof takeUntilOperator & TakeUntilBrand & Function;
|
||||
export const delay = delayOperator as typeof delayOperator & DelayBrand & Function;
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
ScrollStrategy,
|
||||
} from '@angular/cdk/overlay';
|
||||
import {TemplatePortal} from '@angular/cdk/portal';
|
||||
import {filter, first, map, RxChain, switchMap} from '@angular/cdk/rxjs';
|
||||
import {filter, first, RxChain, switchMap, doOperator, delay} from '@angular/cdk/rxjs';
|
||||
import {
|
||||
ChangeDetectorRef,
|
||||
Directive,
|
||||
@@ -284,11 +284,9 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
|
||||
this.openPanel();
|
||||
}
|
||||
|
||||
Promise.resolve().then(() => {
|
||||
if (isArrowKey || this.autocomplete._keyManager.activeItem !== prevActiveItem) {
|
||||
this._scrollToOption();
|
||||
}
|
||||
});
|
||||
if (isArrowKey || this.autocomplete._keyManager.activeItem !== prevActiveItem) {
|
||||
this._scrollToOption();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,9 +354,8 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
|
||||
this.autocomplete._setScrollTop(optionOffset);
|
||||
} else if (optionOffset + AUTOCOMPLETE_OPTION_HEIGHT > panelTop + AUTOCOMPLETE_PANEL_HEIGHT) {
|
||||
// Scroll down to reveal selected option scrolled below the panel bottom
|
||||
const newScrollTop =
|
||||
Math.max(0, optionOffset - AUTOCOMPLETE_PANEL_HEIGHT + AUTOCOMPLETE_OPTION_HEIGHT);
|
||||
this.autocomplete._setScrollTop(newScrollTop);
|
||||
const newScrollTop = optionOffset - AUTOCOMPLETE_PANEL_HEIGHT + AUTOCOMPLETE_OPTION_HEIGHT;
|
||||
this.autocomplete._setScrollTop(Math.max(0, newScrollTop));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,8 +365,12 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
|
||||
*/
|
||||
private _subscribeToClosingActions(): Subscription {
|
||||
const firstStable = first.call(this._zone.onStable.asObservable());
|
||||
const optionChanges = map.call(this.autocomplete.options.changes, () =>
|
||||
this._positionStrategy.recalculateLastPosition());
|
||||
const optionChanges = RxChain.from(this.autocomplete.options.changes)
|
||||
.call(doOperator, () => this._positionStrategy.recalculateLastPosition())
|
||||
// Defer emitting to the stream until the next tick, because changing
|
||||
// bindings in here will cause "changed after checked" errors.
|
||||
.call(delay, 0)
|
||||
.result();
|
||||
|
||||
// When the zone is stable initially, and when the option list changes...
|
||||
return RxChain.from(merge(firstStable, optionChanges))
|
||||
|
||||
@@ -106,22 +106,20 @@ describe('MatAutocomplete', () => {
|
||||
input = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
});
|
||||
|
||||
it('should open the panel when the input is focused', async(() => {
|
||||
it('should open the panel when the input is focused', () => {
|
||||
expect(fixture.componentInstance.trigger.panelOpen)
|
||||
.toBe(false, `Expected panel state to start out closed.`);
|
||||
|
||||
dispatchFakeEvent(input, 'focusin');
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.componentInstance.trigger.panelOpen)
|
||||
.toBe(true, `Expected panel state to read open when input is focused.`);
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toContain('Alabama', `Expected panel to display when input is focused.`);
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toContain('California', `Expected panel to display when input is focused.`);
|
||||
});
|
||||
}));
|
||||
expect(fixture.componentInstance.trigger.panelOpen)
|
||||
.toBe(true, `Expected panel state to read open when input is focused.`);
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toContain('Alabama', `Expected panel to display when input is focused.`);
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toContain('California', `Expected panel to display when input is focused.`);
|
||||
});
|
||||
|
||||
it('should not open the panel on focus if the input is readonly', async(() => {
|
||||
const trigger = fixture.componentInstance.trigger;
|
||||
@@ -137,22 +135,20 @@ describe('MatAutocomplete', () => {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should open the panel programmatically', async(() => {
|
||||
it('should open the panel programmatically', () => {
|
||||
expect(fixture.componentInstance.trigger.panelOpen)
|
||||
.toBe(false, `Expected panel state to start out closed.`);
|
||||
|
||||
fixture.componentInstance.trigger.openPanel();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.componentInstance.trigger.panelOpen)
|
||||
.toBe(true, `Expected panel state to read open when opened programmatically.`);
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toContain('Alabama', `Expected panel to display when opened programmatically.`);
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toContain('California', `Expected panel to display when opened programmatically.`);
|
||||
});
|
||||
}));
|
||||
expect(fixture.componentInstance.trigger.panelOpen)
|
||||
.toBe(true, `Expected panel state to read open when opened programmatically.`);
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toContain('Alabama', `Expected panel to display when opened programmatically.`);
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toContain('California', `Expected panel to display when opened programmatically.`);
|
||||
});
|
||||
|
||||
it('should show the panel when the first open is after the initial zone stabilization',
|
||||
async(() => {
|
||||
@@ -169,7 +165,7 @@ describe('MatAutocomplete', () => {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should close the panel when the user clicks away', async(() => {
|
||||
it('should close the panel when the user clicks away', () => {
|
||||
dispatchFakeEvent(input, 'focusin');
|
||||
fixture.detectChanges();
|
||||
|
||||
@@ -181,7 +177,7 @@ describe('MatAutocomplete', () => {
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toEqual('', `Expected clicking outside the panel to close the panel.`);
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
it('should close the panel when the user taps away on a touch device', async(() => {
|
||||
dispatchFakeEvent(input, 'focus');
|
||||
@@ -245,22 +241,18 @@ describe('MatAutocomplete', () => {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should close the panel programmatically', async(() => {
|
||||
it('should close the panel programmatically', () => {
|
||||
fixture.componentInstance.trigger.openPanel();
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.componentInstance.trigger.closePanel();
|
||||
fixture.detectChanges();
|
||||
fixture.componentInstance.trigger.closePanel();
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
expect(fixture.componentInstance.trigger.panelOpen)
|
||||
.toBe(false, `Expected closing programmatically to set the panel state to closed.`);
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toEqual('', `Expected closing programmatically to close the panel.`);
|
||||
});
|
||||
});
|
||||
}));
|
||||
expect(fixture.componentInstance.trigger.panelOpen)
|
||||
.toBe(false, `Expected closing programmatically to set the panel state to closed.`);
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toEqual('', `Expected closing programmatically to close the panel.`);
|
||||
});
|
||||
|
||||
it('should not throw when attempting to close the panel of a destroyed autocomplete', () => {
|
||||
const trigger = fixture.componentInstance.trigger;
|
||||
@@ -272,28 +264,23 @@ describe('MatAutocomplete', () => {
|
||||
expect(() => trigger.closePanel()).not.toThrow();
|
||||
});
|
||||
|
||||
it('should hide the panel when the options list is empty', async(() => {
|
||||
it('should hide the panel when the options list is empty', fakeAsync(() => {
|
||||
dispatchFakeEvent(input, 'focusin');
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
const panel = overlayContainerElement.querySelector('.mat-autocomplete-panel') as HTMLElement;
|
||||
|
||||
const panel =
|
||||
overlayContainerElement.querySelector('.mat-autocomplete-panel') as HTMLElement;
|
||||
expect(panel.classList)
|
||||
.toContain('mat-autocomplete-visible', `Expected panel to start out visible.`);
|
||||
expect(panel.classList)
|
||||
.toContain('mat-autocomplete-visible', `Expected panel to start out visible.`);
|
||||
|
||||
// Filter down the option list such that no options match the value
|
||||
typeInElement('af', input);
|
||||
fixture.detectChanges();
|
||||
// Filter down the option list such that no options match the value
|
||||
typeInElement('af', input);
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(panel.classList)
|
||||
.toContain('mat-autocomplete-hidden', `Expected panel to hide itself when empty.`);
|
||||
});
|
||||
});
|
||||
expect(panel.classList)
|
||||
.toContain('mat-autocomplete-hidden', `Expected panel to hide itself when empty.`);
|
||||
}));
|
||||
|
||||
it('should keep the label floating until the panel closes', async(() => {
|
||||
@@ -532,31 +519,29 @@ describe('MatAutocomplete', () => {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should fill the text field correctly if value is set to obj programmatically', async(() => {
|
||||
fixture.whenStable().then(() => {
|
||||
it('should fill the text field correctly if value is set to obj programmatically',
|
||||
fakeAsync(() => {
|
||||
fixture.componentInstance.stateCtrl.setValue({code: 'AL', name: 'Alabama'});
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(input.value)
|
||||
.toContain('Alabama', `Expected input to fill with matching option's viewValue.`);
|
||||
});
|
||||
});
|
||||
}));
|
||||
expect(input.value)
|
||||
.toContain('Alabama', `Expected input to fill with matching option's viewValue.`);
|
||||
}));
|
||||
|
||||
it('should clear the text field if value is reset programmatically', async(() => {
|
||||
it('should clear the text field if value is reset programmatically', fakeAsync(() => {
|
||||
typeInElement('Alabama', input);
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.componentInstance.stateCtrl.reset();
|
||||
fixture.componentInstance.stateCtrl.reset();
|
||||
tick();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(input.value).toEqual('', `Expected input value to be empty after reset.`);
|
||||
});
|
||||
});
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
|
||||
expect(input.value).toEqual('', `Expected input value to be empty after reset.`);
|
||||
}));
|
||||
|
||||
it('should disable input in view when disabled programmatically', () => {
|
||||
@@ -577,7 +562,6 @@ describe('MatAutocomplete', () => {
|
||||
.toBe(true, `Expected input underline to display disabled styles.`);
|
||||
});
|
||||
|
||||
|
||||
it('should mark the autocomplete control as dirty as user types', () => {
|
||||
expect(fixture.componentInstance.stateCtrl.dirty)
|
||||
.toBe(false, `Expected control to start out pristine.`);
|
||||
@@ -653,18 +637,15 @@ describe('MatAutocomplete', () => {
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should not focus the option when DOWN key is pressed', async(() => {
|
||||
fixture.whenStable().then(() => {
|
||||
spyOn(fixture.componentInstance.options.first, 'focus');
|
||||
it('should not focus the option when DOWN key is pressed', () => {
|
||||
spyOn(fixture.componentInstance.options.first, 'focus');
|
||||
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
expect(fixture.componentInstance.options.first.focus).not.toHaveBeenCalled();
|
||||
});
|
||||
}));
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
expect(fixture.componentInstance.options.first.focus).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not close the panel when DOWN key is pressed', async(() => {
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
it('should not close the panel when DOWN key is pressed', () => {
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
|
||||
expect(fixture.componentInstance.trigger.panelOpen)
|
||||
.toBe(true, `Expected panel state to stay open when DOWN key is pressed.`);
|
||||
@@ -672,24 +653,17 @@ describe('MatAutocomplete', () => {
|
||||
.toContain('Alabama', `Expected panel to keep displaying when DOWN key is pressed.`);
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toContain('California', `Expected panel to keep displaying when DOWN key is pressed.`);
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
||||
it('should set the active item to the first option when DOWN key is pressed', fakeAsync(() => {
|
||||
tick();
|
||||
it('should set the active item to the first option when DOWN key is pressed', () => {
|
||||
const componentInstance = fixture.componentInstance;
|
||||
const optionEls =
|
||||
overlayContainerElement.querySelectorAll('mat-option') as NodeListOf<HTMLElement>;
|
||||
|
||||
componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(componentInstance.trigger.panelOpen)
|
||||
.toBe(true, 'Expected first down press to open the pane.');
|
||||
|
||||
componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(componentInstance.trigger.activeOption === componentInstance.options.first)
|
||||
@@ -698,30 +672,23 @@ describe('MatAutocomplete', () => {
|
||||
expect(optionEls[1].classList).not.toContain('mat-active');
|
||||
|
||||
componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(componentInstance.trigger.activeOption === componentInstance.options.toArray()[1])
|
||||
.toBe(true, 'Expected second option to be active.');
|
||||
expect(optionEls[0].classList).not.toContain('mat-active');
|
||||
expect(optionEls[1].classList).toContain('mat-active');
|
||||
}));
|
||||
});
|
||||
|
||||
it('should set the active item to the last option when UP key is pressed', fakeAsync(() => {
|
||||
tick();
|
||||
it('should set the active item to the last option when UP key is pressed', () => {
|
||||
const componentInstance = fixture.componentInstance;
|
||||
const optionEls =
|
||||
overlayContainerElement.querySelectorAll('mat-option') as NodeListOf<HTMLElement>;
|
||||
|
||||
componentInstance.trigger._handleKeydown(UP_ARROW_EVENT);
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(componentInstance.trigger.panelOpen)
|
||||
.toBe(true, 'Expected first up press to open the pane.');
|
||||
|
||||
componentInstance.trigger._handleKeydown(UP_ARROW_EVENT);
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(componentInstance.trigger.activeOption === componentInstance.options.last)
|
||||
@@ -730,13 +697,12 @@ describe('MatAutocomplete', () => {
|
||||
expect(optionEls[0].classList).not.toContain('mat-active');
|
||||
|
||||
componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(componentInstance.trigger.activeOption === componentInstance.options.first)
|
||||
.toBe(true, 'Expected first option to be active.');
|
||||
expect(optionEls[0].classList).toContain('mat-active');
|
||||
}));
|
||||
});
|
||||
|
||||
it('should set the active item properly after filtering', fakeAsync(() => {
|
||||
const componentInstance = fixture.componentInstance;
|
||||
@@ -744,12 +710,15 @@ describe('MatAutocomplete', () => {
|
||||
componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
|
||||
it('should set the active item properly after filtering', () => {
|
||||
const componentInstance = fixture.componentInstance;
|
||||
|
||||
typeInElement('o', input);
|
||||
fixture.detectChanges();
|
||||
|
||||
componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
const optionEls =
|
||||
@@ -759,7 +728,7 @@ describe('MatAutocomplete', () => {
|
||||
.toBe(true, 'Expected first option to be active.');
|
||||
expect(optionEls[0].classList).toContain('mat-active');
|
||||
expect(optionEls[1].classList).not.toContain('mat-active');
|
||||
}));
|
||||
});
|
||||
|
||||
it('should fill the text field when an option is selected with ENTER', async(() => {
|
||||
fixture.whenStable().then(() => {
|
||||
@@ -789,39 +758,30 @@ describe('MatAutocomplete', () => {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not prevent the default enter action for a closed panel after a user interaction',
|
||||
fakeAsync(() => {
|
||||
tick();
|
||||
fixture.componentInstance.trigger._handleKeydown(UP_ARROW_EVENT);
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
it('should not prevent the default enter action for a closed panel after a user action', () => {
|
||||
fixture.componentInstance.trigger._handleKeydown(UP_ARROW_EVENT);
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.componentInstance.trigger.closePanel();
|
||||
fixture.detectChanges();
|
||||
fixture.componentInstance.trigger._handleKeydown(ENTER_EVENT);
|
||||
fixture.componentInstance.trigger.closePanel();
|
||||
fixture.detectChanges();
|
||||
fixture.componentInstance.trigger._handleKeydown(ENTER_EVENT);
|
||||
|
||||
expect(ENTER_EVENT.defaultPrevented).toBe(false, 'Default action should not be prevented.');
|
||||
}));
|
||||
expect(ENTER_EVENT.defaultPrevented).toBe(false, 'Default action should not be prevented.');
|
||||
});
|
||||
|
||||
it('should fill the text field, not select an option, when SPACE is entered', async(() => {
|
||||
fixture.whenStable().then(() => {
|
||||
typeInElement('New', input);
|
||||
fixture.detectChanges();
|
||||
it('should fill the text field, not select an option, when SPACE is entered', () => {
|
||||
typeInElement('New', input);
|
||||
fixture.detectChanges();
|
||||
|
||||
const SPACE_EVENT = createKeyboardEvent('keydown', SPACE);
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
const SPACE_EVENT = createKeyboardEvent('keydown', SPACE);
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
fixture.componentInstance.trigger._handleKeydown(SPACE_EVENT);
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.componentInstance.trigger._handleKeydown(SPACE_EVENT);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(input.value)
|
||||
.not.toContain('New York', `Expected option not to be selected on SPACE.`);
|
||||
});
|
||||
});
|
||||
}));
|
||||
expect(input.value).not.toContain('New York', `Expected option not to be selected on SPACE.`);
|
||||
});
|
||||
|
||||
it('should mark the control dirty when selecting an option from the keyboard', async(() => {
|
||||
fixture.whenStable().then(() => {
|
||||
@@ -862,99 +822,76 @@ describe('MatAutocomplete', () => {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should scroll to active options below the fold', fakeAsync(() => {
|
||||
tick();
|
||||
it('should scroll to active options below the fold', () => {
|
||||
const trigger = fixture.componentInstance.trigger;
|
||||
const scrollContainer =
|
||||
document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!;
|
||||
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
tick();
|
||||
trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
fixture.detectChanges();
|
||||
expect(scrollContainer.scrollTop).toEqual(0, `Expected panel not to scroll.`);
|
||||
|
||||
// These down arrows will set the 6th option active, below the fold.
|
||||
[1, 2, 3, 4, 5, 6].forEach(() => {
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
tick();
|
||||
});
|
||||
[1, 2, 3, 4, 5].forEach(() => trigger._handleKeydown(DOWN_ARROW_EVENT));
|
||||
|
||||
// Expect option bottom minus the panel height (288 - 256 = 32)
|
||||
expect(scrollContainer.scrollTop)
|
||||
.toEqual(32, `Expected panel to reveal the sixth option.`);
|
||||
}));
|
||||
});
|
||||
|
||||
it('should scroll to active options on UP arrow', async(() => {
|
||||
fixture.whenStable().then(() => {
|
||||
const scrollContainer =
|
||||
document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!;
|
||||
it('should scroll to active options on UP arrow', () => {
|
||||
const scrollContainer = document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!;
|
||||
|
||||
fixture.componentInstance.trigger._handleKeydown(UP_ARROW_EVENT);
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
// Expect option bottom minus the panel height (528 - 256 = 272)
|
||||
expect(scrollContainer.scrollTop).toEqual(272, `Expected panel to reveal last option.`);
|
||||
});
|
||||
});
|
||||
}));
|
||||
|
||||
it('should not scroll to active options that are fully in the panel', fakeAsync(() => {
|
||||
tick();
|
||||
const scrollContainer =
|
||||
document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!;
|
||||
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
tick();
|
||||
fixture.componentInstance.trigger._handleKeydown(UP_ARROW_EVENT);
|
||||
fixture.detectChanges();
|
||||
|
||||
// Expect option bottom minus the panel height (528 - 256 = 272)
|
||||
expect(scrollContainer.scrollTop).toEqual(272, `Expected panel to reveal last option.`);
|
||||
});
|
||||
|
||||
it('should not scroll to active options that are fully in the panel', () => {
|
||||
const trigger = fixture.componentInstance.trigger;
|
||||
const scrollContainer = document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!;
|
||||
|
||||
trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(scrollContainer.scrollTop).toEqual(0, `Expected panel not to scroll.`);
|
||||
|
||||
// These down arrows will set the 6th option active, below the fold.
|
||||
[1, 2, 3, 4, 5, 6].forEach(() => {
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
tick();
|
||||
});
|
||||
[1, 2, 3, 4, 5].forEach(() => trigger._handleKeydown(DOWN_ARROW_EVENT));
|
||||
|
||||
// Expect option bottom minus the panel height (288 - 256 = 32)
|
||||
expect(scrollContainer.scrollTop)
|
||||
.toEqual(32, `Expected panel to reveal the sixth option.`);
|
||||
|
||||
// These up arrows will set the 2nd option active
|
||||
[4, 3, 2, 1].forEach(() => {
|
||||
fixture.componentInstance.trigger._handleKeydown(UP_ARROW_EVENT);
|
||||
tick();
|
||||
});
|
||||
[4, 3, 2, 1].forEach(() => trigger._handleKeydown(UP_ARROW_EVENT));
|
||||
|
||||
// Expect no scrolling to have occurred. Still showing bottom of 6th option.
|
||||
expect(scrollContainer.scrollTop)
|
||||
.toEqual(32, `Expected panel not to scroll up since sixth option still fully visible.`);
|
||||
}));
|
||||
});
|
||||
|
||||
it('should scroll to active options that are above the panel', fakeAsync(() => {
|
||||
tick();
|
||||
const scrollContainer =
|
||||
document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!;
|
||||
it('should scroll to active options that are above the panel', () => {
|
||||
const trigger = fixture.componentInstance.trigger;
|
||||
const scrollContainer = document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!;
|
||||
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
tick();
|
||||
trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(scrollContainer.scrollTop).toEqual(0, `Expected panel not to scroll.`);
|
||||
|
||||
// These down arrows will set the 7th option active, below the fold.
|
||||
[1, 2, 3, 4, 5, 6, 7].forEach(() => {
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
tick();
|
||||
});
|
||||
[1, 2, 3, 4, 5, 6].forEach(() => trigger._handleKeydown(DOWN_ARROW_EVENT));
|
||||
|
||||
// These up arrows will set the 2nd option as active
|
||||
[5, 4, 3, 2, 1].forEach(() => {
|
||||
fixture.componentInstance.trigger._handleKeydown(UP_ARROW_EVENT);
|
||||
tick();
|
||||
});
|
||||
// These up arrows will set the 2nd option active
|
||||
[5, 4, 3, 2, 1].forEach(() => trigger._handleKeydown(UP_ARROW_EVENT));
|
||||
|
||||
// Expect to show the top of the 2nd option at the top of the panel
|
||||
expect(scrollContainer.scrollTop)
|
||||
.toEqual(48, `Expected panel to scroll up when option is above panel.`);
|
||||
}));
|
||||
});
|
||||
|
||||
it('should close the panel when pressing escape', async(() => {
|
||||
const trigger = fixture.componentInstance.trigger;
|
||||
@@ -964,10 +901,13 @@ describe('MatAutocomplete', () => {
|
||||
input.focus();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(document.activeElement).toBe(input, 'Expected input to be focused.');
|
||||
expect(trigger.panelOpen).toBe(true, 'Expected panel to be open.');
|
||||
|
||||
trigger._handleKeydown(escapeEvent);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(document.activeElement).toBe(input, 'Expected input to continue to be focused.');
|
||||
expect(trigger.panelOpen).toBe(false, 'Expected panel to be closed.');
|
||||
@@ -1153,75 +1093,62 @@ describe('MatAutocomplete', () => {
|
||||
.toEqual('list', 'Expected aria-autocomplete attribute to equal list.');
|
||||
});
|
||||
|
||||
it('should set aria-activedescendant based on the active option', async(() => {
|
||||
it('should set aria-activedescendant based on the active option', fakeAsync(() => {
|
||||
fixture.componentInstance.trigger.openPanel();
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable().then(() => {
|
||||
expect(input.hasAttribute('aria-activedescendant'))
|
||||
.toBe(false, 'Expected aria-activedescendant to be absent if no active item.');
|
||||
|
||||
const DOWN_ARROW_EVENT = createKeyboardEvent('keydown', DOWN_ARROW);
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
expect(input.hasAttribute('aria-activedescendant'))
|
||||
.toBe(false, 'Expected aria-activedescendant to be absent if no active item.');
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(input.getAttribute('aria-activedescendant'))
|
||||
.toEqual(fixture.componentInstance.options.first.id,
|
||||
'Expected aria-activedescendant to match the active item after 1 down arrow.');
|
||||
const DOWN_ARROW_EVENT = createKeyboardEvent('keydown', DOWN_ARROW);
|
||||
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(input.getAttribute('aria-activedescendant'))
|
||||
.toEqual(fixture.componentInstance.options.toArray()[1].id,
|
||||
'Expected aria-activedescendant to match the active item after 2 down arrows.');
|
||||
});
|
||||
});
|
||||
expect(input.getAttribute('aria-activedescendant'))
|
||||
.toEqual(fixture.componentInstance.options.first.id,
|
||||
'Expected aria-activedescendant to match the active item after 1 down arrow.');
|
||||
|
||||
});
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(input.getAttribute('aria-activedescendant'))
|
||||
.toEqual(fixture.componentInstance.options.toArray()[1].id,
|
||||
'Expected aria-activedescendant to match the active item after 2 down arrows.');
|
||||
}));
|
||||
|
||||
it('should set aria-expanded based on whether the panel is open', async(() => {
|
||||
it('should set aria-expanded based on whether the panel is open', () => {
|
||||
expect(input.getAttribute('aria-expanded'))
|
||||
.toBe('false', 'Expected aria-expanded to be false while panel is closed.');
|
||||
|
||||
fixture.componentInstance.trigger.openPanel();
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(input.getAttribute('aria-expanded'))
|
||||
.toBe('true', 'Expected aria-expanded to be true while panel is open.');
|
||||
expect(input.getAttribute('aria-expanded'))
|
||||
.toBe('true', 'Expected aria-expanded to be true while panel is open.');
|
||||
|
||||
fixture.componentInstance.trigger.closePanel();
|
||||
fixture.detectChanges();
|
||||
fixture.componentInstance.trigger.closePanel();
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
expect(input.getAttribute('aria-expanded'))
|
||||
.toBe('false', 'Expected aria-expanded to be false when panel closes again.');
|
||||
});
|
||||
});
|
||||
}));
|
||||
expect(input.getAttribute('aria-expanded'))
|
||||
.toBe('false', 'Expected aria-expanded to be false when panel closes again.');
|
||||
});
|
||||
|
||||
it('should set aria-expanded properly when the panel is hidden', async(() => {
|
||||
fixture.componentInstance.trigger.openPanel();
|
||||
it('should set aria-expanded properly when the panel is hidden', fakeAsync(() => {
|
||||
fixture.componentInstance.trigger.openPanel();
|
||||
fixture.detectChanges();
|
||||
expect(input.getAttribute('aria-expanded'))
|
||||
.toBe('true', 'Expected aria-expanded to be true while panel is open.');
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(input.getAttribute('aria-expanded'))
|
||||
.toBe('true', 'Expected aria-expanded to be true while panel is open.');
|
||||
typeInElement('zz', input);
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
typeInElement('zz', input);
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(input.getAttribute('aria-expanded'))
|
||||
.toBe('false', 'Expected aria-expanded to be false when panel hides itself.');
|
||||
});
|
||||
});
|
||||
});
|
||||
expect(input.getAttribute('aria-expanded'))
|
||||
.toBe('false', 'Expected aria-expanded to be false when panel hides itself.');
|
||||
}));
|
||||
|
||||
it('should set aria-owns based on the attached autocomplete', () => {
|
||||
@@ -1232,7 +1159,6 @@ describe('MatAutocomplete', () => {
|
||||
|
||||
expect(input.getAttribute('aria-owns'))
|
||||
.toEqual(panel.getAttribute('id'), 'Expected aria-owns to match attached autocomplete.');
|
||||
|
||||
});
|
||||
|
||||
it('should restore focus to the input when clicking to select a value', async(() => {
|
||||
@@ -1503,61 +1429,47 @@ describe('MatAutocomplete', () => {
|
||||
}).not.toThrowError();
|
||||
});
|
||||
|
||||
it('should display an empty input when the value is undefined with ngModel', async(() => {
|
||||
it('should display an empty input when the value is undefined with ngModel', () => {
|
||||
const fixture = TestBed.createComponent(AutocompleteWithNgModel);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
const input = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
expect(fixture.debugElement.query(By.css('input')).nativeElement.value).toBe('');
|
||||
});
|
||||
|
||||
expect(input.value).toBe('');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should display the number when the selected option is the number zero', async(() => {
|
||||
it('should display the number when the selected option is the number zero', fakeAsync(() => {
|
||||
const fixture = TestBed.createComponent(AutocompleteWithNumbers);
|
||||
|
||||
fixture.componentInstance.selectedNumber = 0;
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
const input = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
|
||||
expect(input.value).toBe('0');
|
||||
});
|
||||
expect(fixture.debugElement.query(By.css('input')).nativeElement.value).toBe('0');
|
||||
}));
|
||||
|
||||
it('should work when input is wrapped in ngIf', async(() => {
|
||||
it('should work when input is wrapped in ngIf', () => {
|
||||
const fixture = TestBed.createComponent(NgIfAutocomplete);
|
||||
fixture.detectChanges();
|
||||
|
||||
const input = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
dispatchFakeEvent(input, 'focusin');
|
||||
dispatchFakeEvent(fixture.debugElement.query(By.css('input')).nativeElement, 'focusin');
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
fixture.detectChanges();
|
||||
expect(fixture.componentInstance.trigger.panelOpen)
|
||||
.toBe(true, `Expected panel state to read open when input is focused.`);
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toContain('One', `Expected panel to display when input is focused.`);
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toContain('Two', `Expected panel to display when input is focused.`);
|
||||
});
|
||||
|
||||
expect(fixture.componentInstance.trigger.panelOpen)
|
||||
.toBe(true, `Expected panel state to read open when input is focused.`);
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toContain('One', `Expected panel to display when input is focused.`);
|
||||
expect(overlayContainerElement.textContent)
|
||||
.toContain('Two', `Expected panel to display when input is focused.`);
|
||||
});
|
||||
}));
|
||||
|
||||
it('should filter properly with ngIf after setting the active item', fakeAsync(() => {
|
||||
it('should filter properly with ngIf after setting the active item', () => {
|
||||
const fixture = TestBed.createComponent(NgIfAutocomplete);
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.componentInstance.trigger.openPanel();
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
const DOWN_ARROW_EVENT = createKeyboardEvent('keydown', DOWN_ARROW);
|
||||
fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
const input = fixture.debugElement.query(By.css('input')).nativeElement;
|
||||
@@ -1565,16 +1477,16 @@ describe('MatAutocomplete', () => {
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(fixture.componentInstance.matOptions.length).toBe(2);
|
||||
}));
|
||||
});
|
||||
|
||||
it('should throw if the user attempts to open the panel too early', async(() => {
|
||||
it('should throw if the user attempts to open the panel too early', () => {
|
||||
const fixture = TestBed.createComponent(AutocompleteWithoutPanel);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(() => {
|
||||
fixture.componentInstance.trigger.openPanel();
|
||||
}).toThrow(getMatAutocompleteMissingPanelError());
|
||||
}));
|
||||
});
|
||||
|
||||
it('should not throw on init, even if the panel is not defined', fakeAsync(() => {
|
||||
expect(() => {
|
||||
@@ -1677,7 +1589,9 @@ describe('MatAutocomplete', () => {
|
||||
fixture.detectChanges();
|
||||
dispatchFakeEvent(fixture.debugElement.query(By.css('input')).nativeElement, 'focusin');
|
||||
tick(1000);
|
||||
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
|
||||
Promise.resolve().then(() => {
|
||||
let panel = overlayContainerElement.querySelector('.mat-autocomplete-panel') as HTMLElement;
|
||||
@@ -1721,6 +1635,8 @@ describe('MatAutocomplete', () => {
|
||||
|
||||
fixture.componentInstance.states.push('Puerto Rico');
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
|
||||
let options = overlayContainerElement.querySelectorAll('mat-option') as NodeListOf<HTMLElement>;
|
||||
let spy = fixture.componentInstance.optionSelected;
|
||||
|
||||
@@ -123,14 +123,12 @@ export class MatAutocomplete implements AfterContentInit {
|
||||
}
|
||||
|
||||
/** Panel should hide itself when the option list is empty. */
|
||||
_setVisibility(): void {
|
||||
Promise.resolve().then(() => {
|
||||
this.showPanel = !!this.options.length;
|
||||
this._classList['mat-autocomplete-visible'] = this.showPanel;
|
||||
this._classList['mat-autocomplete-hidden'] = !this.showPanel;
|
||||
this._changeDetectorRef.markForCheck();
|
||||
});
|
||||
}
|
||||
_setVisibility() {
|
||||
this.showPanel = !!this.options.length;
|
||||
this._classList['mat-autocomplete-visible'] = this.showPanel;
|
||||
this._classList['mat-autocomplete-hidden'] = !this.showPanel;
|
||||
this._changeDetectorRef.markForCheck();
|
||||
}
|
||||
|
||||
/** Emits the `select` event. */
|
||||
_emitSelectEvent(option: MatOption): void {
|
||||
|
||||
@@ -80,6 +80,7 @@ export const rollupGlobals = {
|
||||
'rxjs/operator/switchMap': 'Rx.Observable.prototype',
|
||||
'rxjs/operator/takeUntil': 'Rx.Observable.prototype',
|
||||
'rxjs/operator/toPromise': 'Rx.Observable.prototype',
|
||||
'rxjs/operator/delay': 'Rx.Observable.prototype',
|
||||
|
||||
'rxjs/add/observable/merge': 'Rx.Observable',
|
||||
'rxjs/add/observable/fromEvent': 'Rx.Observable',
|
||||
|
||||
Reference in New Issue
Block a user