fix(autocomplete): panel not being shown with delay and OnPush change detection (#3977)

Fixes #3955.
This commit is contained in:
Kristiyan Kostadinov
2017-04-19 00:55:08 +02:00
committed by Kara
parent 4bfd2a387c
commit efd348512f
2 changed files with 61 additions and 4 deletions
+53 -2
View File
@@ -1,5 +1,13 @@
import {TestBed, async, fakeAsync, tick, ComponentFixture} from '@angular/core/testing';
import {Component, OnDestroy, QueryList, ViewChild, ViewChildren} from '@angular/core';
import {
Component,
OnDestroy,
QueryList,
ViewChild,
ViewChildren,
ChangeDetectionStrategy,
OnInit,
} from '@angular/core';
import {By} from '@angular/platform-browser';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {MdAutocompleteModule, MdAutocompleteTrigger} from './index';
@@ -38,7 +46,8 @@ describe('MdAutocomplete', () => {
SimpleAutocomplete,
AutocompleteWithoutForms,
NgIfAutocomplete,
AutocompleteWithNgModel
AutocompleteWithNgModel,
AutocompleteWithOnPushDelay
],
providers: [
{provide: OverlayContainer, useFactory: () => {
@@ -1090,6 +1099,24 @@ describe('MdAutocomplete', () => {
expect(Math.ceil(parseFloat(overlayPane.style.width))).toEqual(500);
});
it('should show the panel when the options are initialized later within a component with ' +
'OnPush change detection', fakeAsync(() => {
let fixture = TestBed.createComponent(AutocompleteWithOnPushDelay);
fixture.detectChanges();
dispatchFakeEvent(fixture.debugElement.query(By.css('input')).nativeElement, 'focus');
tick(1000);
fixture.detectChanges();
Promise.resolve().then(() => {
let panel = overlayContainerElement.querySelector('.mat-autocomplete-panel') as HTMLElement;
let visibleClass = 'mat-autocomplete-visible';
fixture.detectChanges();
expect(panel.classList).toContain(visibleClass, `Expected panel to be visible.`);
});
}));
});
@Component({
@@ -1239,6 +1266,30 @@ class AutocompleteWithNgModel {
}
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<md-input-container>
<input type="text" mdInput [mdAutocomplete]="auto">
</md-input-container>
<md-autocomplete #auto="mdAutocomplete">
<md-option *ngFor="let option of options" [value]="option">{{ option }}</md-option>
</md-autocomplete>
`
})
class AutocompleteWithOnPushDelay implements OnInit {
options: string[];
ngOnInit() {
setTimeout(() => {
this.options = ['One'];
}, 1000);
}
}
/** This is a mock keyboard event to test keyboard events in the autocomplete. */
class MockKeyboardEvent {
constructor(public keyCode: number) {}
+8 -2
View File
@@ -7,7 +7,8 @@ import {
QueryList,
TemplateRef,
ViewChild,
ViewEncapsulation
ViewEncapsulation,
ChangeDetectorRef,
} from '@angular/core';
import {MdOption} from '../core';
import {ActiveDescendantKeyManager} from '../core/a11y/activedescendant-key-manager';
@@ -52,6 +53,8 @@ export class MdAutocomplete implements AfterContentInit {
/** Unique ID to be used by autocomplete trigger's "aria-owns" property. */
id: string = `md-autocomplete-${_uniqueAutocompleteIdCounter++}`;
constructor(private _changeDetectorRef: ChangeDetectorRef) { }
ngAfterContentInit() {
this._keyManager = new ActiveDescendantKeyManager(this.options).withWrap();
}
@@ -68,7 +71,10 @@ export class MdAutocomplete implements AfterContentInit {
/** Panel should hide itself when the option list is empty. */
_setVisibility() {
Promise.resolve().then(() => this.showPanel = !!this.options.length);
Promise.resolve().then(() => {
this.showPanel = !!this.options.length;
this._changeDetectorRef.markForCheck();
});
}
/** Sets a class on the panel based on its position (used to set y-offset). */