From 01467b0658c4aff91ac0c932ea7291aa720e9a14 Mon Sep 17 00:00:00 2001 From: mmalerba Date: Wed, 5 Dec 2018 15:31:14 -0800 Subject: [PATCH 1/6] Revert "Revert "fix(autocomplete): auto-highlighted first option not display correctly if the floating label is disabled" (#14396)" This reverts commit aa17fbd69fb2d4a8ff2d7efa6e8c6f9699ab8f67. --- src/lib/autocomplete/autocomplete-trigger.ts | 1 + src/lib/autocomplete/autocomplete.spec.ts | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/lib/autocomplete/autocomplete-trigger.ts b/src/lib/autocomplete/autocomplete-trigger.ts index fe7ef1fb7215..f0473f5473f2 100644 --- a/src/lib/autocomplete/autocomplete-trigger.ts +++ b/src/lib/autocomplete/autocomplete-trigger.ts @@ -493,6 +493,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy { switchMap(() => { this._resetActiveItem(); this.autocomplete._setVisibility(); + this._changeDetectorRef.detectChanges(); if (this.panelOpen) { this._overlayRef!.updatePosition(); diff --git a/src/lib/autocomplete/autocomplete.spec.ts b/src/lib/autocomplete/autocomplete.spec.ts index 1b2c205c860c..5576e084c17b 100644 --- a/src/lib/autocomplete/autocomplete.spec.ts +++ b/src/lib/autocomplete/autocomplete.spec.ts @@ -1644,6 +1644,22 @@ describe('MatAutocomplete', () => { .toContain('mat-active', 'Expected first option to be highlighted.'); })); + it('should be able to preselect the first option when the floating label is disabled', + fakeAsync(() => { + fixture.componentInstance.floatLabel = 'never'; + fixture.componentInstance.trigger.autocomplete.autoActiveFirstOption = true; + fixture.detectChanges(); + + fixture.componentInstance.trigger.openPanel(); + fixture.detectChanges(); + zone.simulateZoneExit(); + // Note: should not have a detectChanges call here + // in order for the test to fail when it's supposed to. + + expect(overlayContainerElement.querySelectorAll('mat-option')[0].classList) + .toContain('mat-active', 'Expected first option to be highlighted.'); + })); + it('should be able to configure preselecting the first option globally', fakeAsync(() => { overlayContainer.ngOnDestroy(); fixture.destroy(); From 3e91714c66987435b4e6af893185b13baf6d732c Mon Sep 17 00:00:00 2001 From: mmalerba Date: Wed, 5 Dec 2018 15:31:14 -0800 Subject: [PATCH 2/6] Revert "fix(drag-drop): error on touch end (#14392)" This reverts commit 53cecbb5f930c6d3795dca155fea60838594ff9a. From 373f57d9c56c38c0926754d08717cb39a74c7490 Mon Sep 17 00:00:00 2001 From: mmalerba Date: Wed, 5 Dec 2018 15:31:14 -0800 Subject: [PATCH 3/6] Revert "fix(menu): reduce specificity of icon selector (#14389)" This reverts commit 74e945adc91df1e0328cc5b7ee5992fabb18ca7e. From 2dee5f21501bf67b6c961c79d42414e2c11f7115 Mon Sep 17 00:00:00 2001 From: mmalerba Date: Wed, 5 Dec 2018 15:31:14 -0800 Subject: [PATCH 4/6] Revert "fix(drag-drop): throw better error when attaching to non-element node (#14221)" This reverts commit 31f0e6d5adce6005f0bf0d395798409b8c6177c8. From 86bc7c8d2dde2b1356a3678a8be040d10dce3d0b Mon Sep 17 00:00:00 2001 From: mmalerba Date: Wed, 5 Dec 2018 15:31:14 -0800 Subject: [PATCH 5/6] Revert "fix(autocomplete): auto-highlighted first option not display correctly if the floating label is disabled (#13774)" This reverts commit c99c512106ac301580c15c2d24f7917c8f0ca827. --- src/lib/autocomplete/autocomplete-trigger.ts | 1 - src/lib/autocomplete/autocomplete.spec.ts | 16 ---------------- 2 files changed, 17 deletions(-) diff --git a/src/lib/autocomplete/autocomplete-trigger.ts b/src/lib/autocomplete/autocomplete-trigger.ts index f0473f5473f2..fe7ef1fb7215 100644 --- a/src/lib/autocomplete/autocomplete-trigger.ts +++ b/src/lib/autocomplete/autocomplete-trigger.ts @@ -493,7 +493,6 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy { switchMap(() => { this._resetActiveItem(); this.autocomplete._setVisibility(); - this._changeDetectorRef.detectChanges(); if (this.panelOpen) { this._overlayRef!.updatePosition(); diff --git a/src/lib/autocomplete/autocomplete.spec.ts b/src/lib/autocomplete/autocomplete.spec.ts index 5576e084c17b..1b2c205c860c 100644 --- a/src/lib/autocomplete/autocomplete.spec.ts +++ b/src/lib/autocomplete/autocomplete.spec.ts @@ -1644,22 +1644,6 @@ describe('MatAutocomplete', () => { .toContain('mat-active', 'Expected first option to be highlighted.'); })); - it('should be able to preselect the first option when the floating label is disabled', - fakeAsync(() => { - fixture.componentInstance.floatLabel = 'never'; - fixture.componentInstance.trigger.autocomplete.autoActiveFirstOption = true; - fixture.detectChanges(); - - fixture.componentInstance.trigger.openPanel(); - fixture.detectChanges(); - zone.simulateZoneExit(); - // Note: should not have a detectChanges call here - // in order for the test to fail when it's supposed to. - - expect(overlayContainerElement.querySelectorAll('mat-option')[0].classList) - .toContain('mat-active', 'Expected first option to be highlighted.'); - })); - it('should be able to configure preselecting the first option globally', fakeAsync(() => { overlayContainer.ngOnDestroy(); fixture.destroy(); From f6cf9464ff06d12dcdd4771f1a807a88c4c61ae9 Mon Sep 17 00:00:00 2001 From: mmalerba Date: Wed, 5 Dec 2018 15:31:14 -0800 Subject: [PATCH 6/6] Revert "fix(autocomplete): update template when changing autocomplete in trigger (#13814)" This reverts commit 904a5eaecab63f3984a43640ad45ecf96ab74021. --- src/lib/autocomplete/autocomplete-trigger.ts | 35 ++++++--------- src/lib/autocomplete/autocomplete.spec.ts | 47 -------------------- src/lib/autocomplete/autocomplete.ts | 13 +----- 3 files changed, 15 insertions(+), 80 deletions(-) diff --git a/src/lib/autocomplete/autocomplete-trigger.ts b/src/lib/autocomplete/autocomplete-trigger.ts index fe7ef1fb7215..ea86763a5722 100644 --- a/src/lib/autocomplete/autocomplete-trigger.ts +++ b/src/lib/autocomplete/autocomplete-trigger.ts @@ -15,6 +15,7 @@ import { PositionStrategy, ScrollStrategy, } from '@angular/cdk/overlay'; +import {TemplatePortal} from '@angular/cdk/portal'; import {DOCUMENT} from '@angular/common'; import {filter, take, switchMap, delay, tap, map} from 'rxjs/operators'; import { @@ -29,6 +30,7 @@ import { NgZone, OnDestroy, Optional, + ViewContainerRef, } from '@angular/core'; import {ViewportRuler} from '@angular/cdk/scrolling'; import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms'; @@ -115,9 +117,9 @@ export function getMatAutocompleteMissingPanelError(): Error { }) export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy { private _overlayRef: OverlayRef | null; + private _portal: TemplatePortal; private _componentDestroyed = false; private _autocompleteDisabled = false; - private _autocomplete: MatAutocomplete; private _scrollStrategy: () => ScrollStrategy; /** Old value of the native input. Used to work around issues with the `input` event on IE. */ @@ -130,7 +132,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy { private _manuallyFloatingLabel = false; /** The subscription for closing actions (some are bound to document). */ - private _closingActionsSubscription = Subscription.EMPTY; + private _closingActionsSubscription: Subscription; /** Subscription to viewport size changes. */ private _viewportSubscription = Subscription.EMPTY; @@ -164,12 +166,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy { _onTouched = () => {}; /** The autocomplete panel to be attached to this trigger. */ - @Input('matAutocomplete') - get autocomplete(): MatAutocomplete { return this._autocomplete; } - set autocomplete(value: MatAutocomplete) { - this._autocomplete = value; - this._detachOverlay(); - } + @Input('matAutocomplete') autocomplete: MatAutocomplete; /** * Reference relative to which to position the autocomplete panel. @@ -193,8 +190,8 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy { this._autocompleteDisabled = coerceBooleanProperty(value); } - constructor(private _element: ElementRef, - private _overlay: Overlay, + constructor(private _element: ElementRef, private _overlay: Overlay, + private _viewContainerRef: ViewContainerRef, private _zone: NgZone, private _changeDetectorRef: ChangeDetectorRef, @Inject(MAT_AUTOCOMPLETE_SCROLL_STRATEGY) scrollStrategy: any, @@ -249,9 +246,12 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy { this.autocomplete.closed.emit(); } - this.autocomplete._isOpen = false; - this._detachOverlay(); + this.autocomplete._isOpen = this._overlayAttached = false; + if (this._overlayRef && this._overlayRef.hasAttached()) { + this._overlayRef.detach(); + this._closingActionsSubscription.unsubscribe(); + } // Note that in some cases this can end up being called after the component is destroyed. // Add a check to ensure that we don't try to run change detection on a destroyed view. @@ -570,6 +570,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy { } if (!this._overlayRef) { + this._portal = new TemplatePortal(this.autocomplete.template, this._viewContainerRef); this._overlayRef = this._overlay.create(this._getOverlayConfig()); // Use the `keydownEvents` in order to take advantage of @@ -596,7 +597,7 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy { } if (this._overlayRef && !this._overlayRef.hasAttached()) { - this._overlayRef.attach(this.autocomplete._portal); + this._overlayRef.attach(this._portal); this._closingActionsSubscription = this._subscribeToClosingActions(); } @@ -612,14 +613,6 @@ export class MatAutocompleteTrigger implements ControlValueAccessor, OnDestroy { } } - private _detachOverlay() { - this._overlayAttached = false; - this._closingActionsSubscription.unsubscribe(); - if (this._overlayRef) { - this._overlayRef.detach(); - } - } - private _getOverlayConfig(): OverlayConfig { return new OverlayConfig({ positionStrategy: this._getOverlayPosition(), diff --git a/src/lib/autocomplete/autocomplete.spec.ts b/src/lib/autocomplete/autocomplete.spec.ts index 1b2c205c860c..055cf6da1e5d 100644 --- a/src/lib/autocomplete/autocomplete.spec.ts +++ b/src/lib/autocomplete/autocomplete.spec.ts @@ -2233,35 +2233,6 @@ describe('MatAutocomplete', () => { expect(formControl.value).toBe('Cal', 'Expected new value to be propagated to model'); })); - it('should work when dynamically changing the autocomplete', () => { - const fixture = createComponent(DynamicallyChangingAutocomplete); - fixture.detectChanges(); - const input = fixture.debugElement.query(By.css('input')).nativeElement; - - dispatchFakeEvent(input, 'focusin'); - fixture.detectChanges(); - - expect(overlayContainerElement.textContent).toContain('First', - `Expected panel to display the option of the first autocomplete.`); - expect(overlayContainerElement.textContent).not.toContain('Second', - `Expected panel to not display the option of the second autocomplete.`); - - dispatchFakeEvent(document, 'click'); - fixture.detectChanges(); - - fixture.componentInstance.trigger.autocomplete = fixture.componentInstance.autoTow; - fixture.detectChanges(); - - dispatchFakeEvent(input, 'focusin'); - fixture.detectChanges(); - - expect(overlayContainerElement.textContent).not.toContain('First', - `Expected panel to not display the option of the first autocomplete.`); - expect(overlayContainerElement.textContent).toContain('Second', - `Expected panel to display the option of the second autocomplete.`); - - }); - }); @Component({ @@ -2648,21 +2619,3 @@ class AutocompleteWithNativeAutocompleteAttribute { }) class InputWithoutAutocompleteAndDisabled { } - -@Component({ - template: ` - - - First - - - - Second - - `, -}) -class DynamicallyChangingAutocomplete { - @ViewChild('autoOne') autoOne: MatAutocomplete; - @ViewChild('autoTow') autoTow: MatAutocomplete; - @ViewChild(MatAutocompleteTrigger) trigger: MatAutocompleteTrigger; -} diff --git a/src/lib/autocomplete/autocomplete.ts b/src/lib/autocomplete/autocomplete.ts index 8c31c34e4c47..bbd5a0ca1b26 100644 --- a/src/lib/autocomplete/autocomplete.ts +++ b/src/lib/autocomplete/autocomplete.ts @@ -24,8 +24,6 @@ import { TemplateRef, ViewChild, ViewEncapsulation, - AfterViewInit, - ViewContainerRef, } from '@angular/core'; import { CanDisableRipple, @@ -35,7 +33,6 @@ import { MatOption, mixinDisableRipple, } from '@angular/material/core'; -import {TemplatePortal} from '@angular/cdk/portal'; /** @@ -95,7 +92,7 @@ export function MAT_AUTOCOMPLETE_DEFAULT_OPTIONS_FACTORY(): MatAutocompleteDefau ] }) export class MatAutocomplete extends _MatAutocompleteMixinBase implements AfterContentInit, - AfterViewInit, CanDisableRipple { + CanDisableRipple { /** Manages active item in option list based on key events. */ _keyManager: ActiveDescendantKeyManager; @@ -103,9 +100,6 @@ export class MatAutocomplete extends _MatAutocompleteMixinBase implements AfterC /** Whether the autocomplete panel should be visible, depending on option length. */ showPanel: boolean = false; - /** @docs-private */ - _portal: TemplatePortal; - /** Whether the autocomplete panel is open. */ get isOpen(): boolean { return this._isOpen && this.showPanel; } _isOpen: boolean = false; @@ -171,17 +165,12 @@ export class MatAutocomplete extends _MatAutocompleteMixinBase implements AfterC constructor( private _changeDetectorRef: ChangeDetectorRef, private _elementRef: ElementRef, - private _viewContainerRef: ViewContainerRef, @Inject(MAT_AUTOCOMPLETE_DEFAULT_OPTIONS) defaults: MatAutocompleteDefaultOptions) { super(); this._autoActiveFirstOption = !!defaults.autoActiveFirstOption; } - ngAfterViewInit() { - this._portal = new TemplatePortal(this.template, this._viewContainerRef); - } - ngAfterContentInit() { this._keyManager = new ActiveDescendantKeyManager(this.options).withWrap(); // Set the initial visibility state.