From 36aa416b4dcd6b40f0d6d8f4484a2be9cb74e793 Mon Sep 17 00:00:00 2001 From: Sergey Andrievskiy Date: Fri, 19 Apr 2019 14:27:38 +0300 Subject: [PATCH] fix(overlay): set context on component portals before first cd run (#1395) --- .../cdk/overlay/overlay-container.spec.ts | 58 +++++++++++++++++++ .../cdk/overlay/overlay-container.ts | 5 +- .../components/popover/popover.component.ts | 3 +- .../components/window/window.component.ts | 3 +- 4 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 src/framework/theme/components/cdk/overlay/overlay-container.spec.ts diff --git a/src/framework/theme/components/cdk/overlay/overlay-container.spec.ts b/src/framework/theme/components/cdk/overlay/overlay-container.spec.ts new file mode 100644 index 0000000000..447302171d --- /dev/null +++ b/src/framework/theme/components/cdk/overlay/overlay-container.spec.ts @@ -0,0 +1,58 @@ +import { Component, NgModule, OnInit, ViewChild } from '@angular/core'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { NbComponentPortal, NbOverlayContainerComponent, NbOverlayModule } from '@nebular/theme'; + +@Component({ + template: ` + + `, +}) +export class NbOverlayContainerTestComponent { + @ViewChild(NbOverlayContainerComponent) overlayContainer: NbOverlayContainerComponent; +} + +@Component({ + template: `{{ contextProperty }}`, +}) +export class NbOverlayTestComponent implements OnInit { + contextProperty; + + isFirstOnChangesCall = true; + contextPropertyValueOnFirstCdRun; + ngOnInit() { + if (this.isFirstOnChangesCall) { + this.contextPropertyValueOnFirstCdRun = this.contextProperty; + this.isFirstOnChangesCall = false; + } + } +} + +// Has to define test module since there is no way to specify entry components +// in 'TestBed.configureTestingModule'. +@NgModule({ + imports: [ NbOverlayModule.forRoot() ], + declarations: [ NbOverlayContainerTestComponent, NbOverlayTestComponent ], + entryComponents: [ NbOverlayTestComponent ], +}) +export class NbOverlayTestModule {} + +describe('NbOverlayContainerComponent', () => { + let fixture: ComponentFixture; + let overlayContainer: NbOverlayContainerComponent; + + beforeEach(() => { + TestBed.configureTestingModule({ imports: [ NbOverlayTestModule ] }); + + fixture = TestBed.createComponent(NbOverlayContainerTestComponent); + fixture.detectChanges(); + overlayContainer = fixture.componentInstance.overlayContainer; + }); + + it('should set context before change detection run', () => { + const context = { contextProperty: 'contextProperty' }; + const portal: NbComponentPortal = new NbComponentPortal(NbOverlayTestComponent); + const portalRef = overlayContainer.attachComponentPortal(portal, context); + + expect(portalRef.instance.contextPropertyValueOnFirstCdRun).toEqual(context.contextProperty); + }); +}); diff --git a/src/framework/theme/components/cdk/overlay/overlay-container.ts b/src/framework/theme/components/cdk/overlay/overlay-container.ts index 49910616db..0beed48b45 100644 --- a/src/framework/theme/components/cdk/overlay/overlay-container.ts +++ b/src/framework/theme/components/cdk/overlay/overlay-container.ts @@ -72,9 +72,12 @@ export class NbOverlayContainerComponent { return !!this.content; } - attachComponentPortal(portal: NbComponentPortal): ComponentRef { + attachComponentPortal(portal: NbComponentPortal, context?: Object): ComponentRef { portal.injector = this.createChildInjector(portal.componentFactoryResolver); const componentRef = this.portalOutlet.attachComponentPortal(portal); + if (context) { + Object.assign(componentRef.instance, context); + } componentRef.changeDetectorRef.markForCheck(); componentRef.changeDetectorRef.detectChanges(); this.isAttached = true; diff --git a/src/framework/theme/components/popover/popover.component.ts b/src/framework/theme/components/popover/popover.component.ts index ef2c42dce0..31d40f383e 100644 --- a/src/framework/theme/components/popover/popover.component.ts +++ b/src/framework/theme/components/popover/popover.component.ts @@ -73,8 +73,7 @@ export class NbPopoverComponent extends NbPositionedContainer implements NbRende protected attachComponent() { const portal = new NbComponentPortal(this.content, null, null, this.cfr); - const ref = this.overlayContainer.attachComponentPortal(portal); - Object.assign(ref.instance, this.context); + const ref = this.overlayContainer.attachComponentPortal(portal, this.context); ref.changeDetectorRef.detectChanges(); } diff --git a/src/framework/theme/components/window/window.component.ts b/src/framework/theme/components/window/window.component.ts index 0944390bcd..4aace950f5 100644 --- a/src/framework/theme/components/window/window.component.ts +++ b/src/framework/theme/components/window/window.component.ts @@ -150,8 +150,7 @@ export class NbWindowComponent implements OnInit, AfterViewChecked, OnDestroy { protected attachComponent() { const portal = new NbComponentPortal(this.content as Type, null, null, this.cfr); - const ref = this.overlayContainer.attachComponentPortal(portal); - Object.assign(ref.instance, this.context); + const ref = this.overlayContainer.attachComponentPortal(portal, this.context); ref.changeDetectorRef.detectChanges(); } }