From 99fc6685aa16edba2a828a427787f99ded3a54d7 Mon Sep 17 00:00:00 2001 From: Jeremy Elbourn Date: Wed, 14 Jun 2017 17:10:49 -0700 Subject: [PATCH] Revert "fix(portal): detect changes for portal hostview while before attaching. (#4370)" (#5131) --- src/lib/core/portal/dom-portal-host.ts | 10 +++-- src/lib/core/portal/portal.spec.ts | 22 +---------- src/lib/datepicker/datepicker-content.html | 16 ++++---- src/lib/datepicker/datepicker.spec.ts | 44 +++++++++++++++++++++- src/lib/datepicker/datepicker.ts | 2 +- src/lib/snack-bar/snack-bar.ts | 5 +++ 6 files changed, 65 insertions(+), 34 deletions(-) diff --git a/src/lib/core/portal/dom-portal-host.ts b/src/lib/core/portal/dom-portal-host.ts index 445fe135f4f5..dc64fdc88bc2 100644 --- a/src/lib/core/portal/dom-portal-host.ts +++ b/src/lib/core/portal/dom-portal-host.ts @@ -37,17 +37,21 @@ export class DomPortalHost extends BasePortalHost { */ attachComponentPortal(portal: ComponentPortal): ComponentRef { let componentFactory = this._componentFactoryResolver.resolveComponentFactory(portal.component); - let componentRef = componentFactory.create(portal.injector || this._defaultInjector); - componentRef.hostView.detectChanges(); + let componentRef: ComponentRef; // If the portal specifies a ViewContainerRef, we will use that as the attachment point // for the component (in terms of Angular's component tree, not rendering). // When the ViewContainerRef is missing, we use the factory to create the component directly // and then manually attach the view to the application. if (portal.viewContainerRef) { - portal.viewContainerRef.insert(componentRef.hostView); + componentRef = portal.viewContainerRef.createComponent( + componentFactory, + portal.viewContainerRef.length, + portal.injector || portal.viewContainerRef.parentInjector); + this.setDisposeFn(() => componentRef.destroy()); } else { + componentRef = componentFactory.create(portal.injector || this._defaultInjector); this._appRef.attachView(componentRef.hostView); this.setDisposeFn(() => { this._appRef.detachView(componentRef.hostView); diff --git a/src/lib/core/portal/portal.spec.ts b/src/lib/core/portal/portal.spec.ts index 16dc8c8058e5..6ba347c833b1 100644 --- a/src/lib/core/portal/portal.spec.ts +++ b/src/lib/core/portal/portal.spec.ts @@ -368,12 +368,6 @@ describe('Portals', () => { expect(spy).toHaveBeenCalled(); }); - - it('should run change detection in the created component when a ComponentPortal is attached', - () => { - host.attach(new ComponentPortal(ComponentWithBoundVariable, someViewContainerRef)); - expect(someDomElement.textContent).toContain('initial value'); - }); }); }); @@ -410,15 +404,6 @@ class ArbitraryViewContainerRefComponent { constructor(public viewContainerRef: ViewContainerRef, public injector: Injector) { } } -/** Simple component with a bound variable in the template */ -@Component({ - selector: 'bound-text', - template: '

{{text}}

' -}) -class ComponentWithBoundVariable { - text: string = 'initial value'; -} - /** Test-bed component that contains a portal host and a couple of template portals. */ @Component({ @@ -468,12 +453,7 @@ class PortalTestApp { // Create a real (non-test) NgModule as a workaround for // https://github.com/angular/angular/issues/10760 -const TEST_COMPONENTS = [ - PortalTestApp, - ArbitraryViewContainerRefComponent, - PizzaMsg, - ComponentWithBoundVariable -]; +const TEST_COMPONENTS = [PortalTestApp, ArbitraryViewContainerRefComponent, PizzaMsg]; @NgModule({ imports: [CommonModule, PortalModule], exports: TEST_COMPONENTS, diff --git a/src/lib/datepicker/datepicker-content.html b/src/lib/datepicker/datepicker-content.html index 86829a041fec..0f3a70ec7dff 100644 --- a/src/lib/datepicker/datepicker-content.html +++ b/src/lib/datepicker/datepicker-content.html @@ -1,10 +1,10 @@ + [id]="datepicker.id" + [startAt]="datepicker.startAt" + [startView]="datepicker.startView" + [minDate]="datepicker._minDate" + [maxDate]="datepicker._maxDate" + [dateFilter]="datepicker._dateFilter" + [selected]="datepicker._selected" + (selectedChange)="datepicker._selectAndClose($event)"> diff --git a/src/lib/datepicker/datepicker.spec.ts b/src/lib/datepicker/datepicker.spec.ts index bd1b48ba8e5a..dd2b266b5282 100644 --- a/src/lib/datepicker/datepicker.spec.ts +++ b/src/lib/datepicker/datepicker.spec.ts @@ -34,7 +34,7 @@ describe('MdDatepicker', () => { let adapter = new NativeDateAdapter(); adapter.setLocale('en-US'); return adapter; - }} + }}, ], declarations: [ DatepickerWithFilterAndValidation, @@ -42,6 +42,7 @@ describe('MdDatepicker', () => { DatepickerWithMinAndMaxValidation, DatepickerWithNgModel, DatepickerWithStartAt, + DatepickerWithStartView, DatepickerWithToggle, InputContainerDatepicker, MultiInputDatepicker, @@ -203,6 +204,35 @@ describe('MdDatepicker', () => { }); }); + describe('datepicker with startView', () => { + let fixture: ComponentFixture; + let testComponent: DatepickerWithStartView; + + beforeEach(async(() => { + fixture = TestBed.createComponent(DatepickerWithStartView); + fixture.detectChanges(); + + testComponent = fixture.componentInstance; + })); + + afterEach(async(() => { + testComponent.datepicker.close(); + fixture.detectChanges(); + })); + + it('should start at the specified view', () => { + testComponent.datepicker.open(); + fixture.detectChanges(); + + const firstCalendarCell = document.querySelector('.mat-calendar-body-cell'); + + // When the calendar is in year view, the first cell should be for a month rather than + // for a date. + expect(firstCalendarCell.textContent) + .toBe('JAN', 'Expected the calendar to be in year-view'); + }); + }); + describe('datepicker with ngModel', () => { let fixture: ComponentFixture; let testComponent: DatepickerWithNgModel; @@ -698,6 +728,18 @@ class DatepickerWithStartAt { } +@Component({ + template: ` + + + `, +}) +class DatepickerWithStartView { + date = new Date(2020, JAN, 1); + @ViewChild('d') datepicker: MdDatepicker; +} + + @Component({ template: ``, }) diff --git a/src/lib/datepicker/datepicker.ts b/src/lib/datepicker/datepicker.ts index 0f11519edc8b..9bd5b4903a52 100644 --- a/src/lib/datepicker/datepicker.ts +++ b/src/lib/datepicker/datepicker.ts @@ -57,7 +57,7 @@ let datepickerUid = 0; styleUrls: ['datepicker-content.css'], host: { 'class': 'mat-datepicker-content', - '[class.mat-datepicker-content-touch]': 'datepicker?.touchUi', + '[class.mat-datepicker-content-touch]': 'datepicker.touchUi', '(keydown)': '_handleKeydown($event)', }, encapsulation: ViewEncapsulation.None, diff --git a/src/lib/snack-bar/snack-bar.ts b/src/lib/snack-bar/snack-bar.ts index 84ef02aa59d2..3ab3bae0470b 100644 --- a/src/lib/snack-bar/snack-bar.ts +++ b/src/lib/snack-bar/snack-bar.ts @@ -131,6 +131,11 @@ export class MdSnackBar { let containerRef: ComponentRef = overlayRef.attach(containerPortal); containerRef.instance.snackBarConfig = config; + // The snackbar animation needs the content to be resolved in order to transform the bar + // out of the view initially (so it can slide in). To make the content resolve, we manually + // detect changes. + containerRef.changeDetectorRef.detectChanges(); + return containerRef.instance; }