From 515636ce75fc1f396c7500fe90e3db31ed0e6095 Mon Sep 17 00:00:00 2001 From: Nikita Poltoratsky Date: Tue, 20 Feb 2018 15:10:52 +0200 Subject: [PATCH] feat(theme): add capability append component to the layout top by its factory (#253) --- e2e/layout-dynamic.e2e-spec.ts | 22 ++++++++++++++++++- .../theme-dynamic-test.component.ts | 10 +++++++-- .../components/layout/layout.component.ts | 7 +++--- .../components/popover/popover.directive.ts | 8 ++++--- src/framework/theme/services/theme.service.ts | 13 ++++++++--- 5 files changed, 47 insertions(+), 13 deletions(-) diff --git a/e2e/layout-dynamic.e2e-spec.ts b/e2e/layout-dynamic.e2e-spec.ts index 5b5c0d98f3..0e1706a252 100644 --- a/e2e/layout-dynamic.e2e-spec.ts +++ b/e2e/layout-dynamic.e2e-spec.ts @@ -18,7 +18,7 @@ describe('nb-layout theme', () => { }); }); - it('should insert append into nb-layout', () => { + it('should append into nb-layout', () => { const button = element(by.css('#add-dynamic')); @@ -38,6 +38,26 @@ describe('nb-layout theme', () => { }); }); + it('should append by factory into nb-layout', () => { + + const button = element(by.css('#add-dynamic-by-factory')); + + button.click().then(() => { + return browser.driver.wait(() => { + return element(by.css('nb-layout')).$$('*').first().getTagName().then(value => { + return value === 'nb-dynamic-to-add'; + }); + }, 10000); + }); + + element(by.css('nb-layout')).$$('*').first().getTagName().then(value => { + expect(value).toMatch('nb-dynamic-to-add'); + }); + element(by.css('nb-layout')).$$('*').get(1).getTagName().then(value => { + expect(value).toMatch('div'); + }); + }); + it('should clear dymamic nb-layout area', () => { const buttonAdd = element(by.css('#add-dynamic')); diff --git a/src/app/layout-test/theme-dynamic-test.component.ts b/src/app/layout-test/theme-dynamic-test.component.ts index 307d47eac2..f0100d5dbe 100644 --- a/src/app/layout-test/theme-dynamic-test.component.ts +++ b/src/app/layout-test/theme-dynamic-test.component.ts @@ -4,7 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. */ -import { Component } from '@angular/core'; +import { Component, ComponentFactoryResolver } from '@angular/core'; import { NbThemeService } from '@nebular/theme'; @@ -25,6 +25,7 @@ export class NbDynamicToAddComponent {} Akveo + @@ -49,12 +50,17 @@ export class NbDynamicToAddComponent {} `, }) export class NbThemeDynamicTestComponent { - constructor(private themeService: NbThemeService) {} + constructor(private themeService: NbThemeService, private componentFactoryResolver: ComponentFactoryResolver) {} addDynamicComponent() { this.themeService.appendToLayoutTop(NbDynamicToAddComponent).subscribe(cRef => console.info(cRef)); } + addDynamicByFactory() { + const factory = this.componentFactoryResolver.resolveComponentFactory(NbDynamicToAddComponent); + this.themeService.appendToLayoutTop(factory).subscribe(cRef => console.info(cRef)); + } + clearDynamicComponents() { this.themeService.clearLayoutTop().subscribe(res => console.info(res)); } diff --git a/src/framework/theme/components/layout/layout.component.ts b/src/framework/theme/components/layout/layout.component.ts index 9ea23547f2..855fc1217d 100644 --- a/src/framework/theme/components/layout/layout.component.ts +++ b/src/framework/theme/components/layout/layout.component.ts @@ -6,7 +6,7 @@ import { AfterViewInit, Component, ComponentFactoryResolver, ElementRef, HostBinding, HostListener, Input, OnDestroy, - Renderer2, ViewChild, ViewContainerRef, OnInit, Inject, PLATFORM_ID, + Renderer2, ViewChild, ViewContainerRef, OnInit, ComponentFactory, Inject, PLATFORM_ID, } from '@angular/core'; import { DOCUMENT, isPlatformBrowser } from '@angular/common'; import { Router, NavigationEnd } from '@angular/router'; @@ -344,9 +344,8 @@ export class NbLayoutComponent implements AfterViewInit, OnInit, OnDestroy { .pipe( takeWhile(() => this.alive), ) - .subscribe((data: { component: any, listener: Subject }) => { - const componentFactory = this.componentFactoryResolver.resolveComponentFactory(data.component); - const componentRef = this.veryTopRef.createComponent(componentFactory); + .subscribe((data: { factory: ComponentFactory, listener: Subject }) => { + const componentRef = this.veryTopRef.createComponent(data.factory); data.listener.next(componentRef); data.listener.complete(); }); diff --git a/src/framework/theme/components/popover/popover.directive.ts b/src/framework/theme/components/popover/popover.directive.ts index 9b18c10f5c..9650b7e1a6 100644 --- a/src/framework/theme/components/popover/popover.directive.ts +++ b/src/framework/theme/components/popover/popover.directive.ts @@ -5,8 +5,8 @@ */ import { - ComponentRef, Directive, ElementRef, HostListener, - Input, OnDestroy, OnInit, PLATFORM_ID, Inject, + ComponentFactoryResolver, ComponentRef, Directive, ElementRef, HostListener, Input, OnDestroy, + OnInit, PLATFORM_ID, Inject, } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; import { NbPositioningHelper } from './helpers/positioning.helper'; @@ -137,6 +137,7 @@ export class NbPopoverDirective implements OnInit, OnDestroy { constructor( private hostRef: ElementRef, private themeService: NbThemeService, + private componentFactoryResolver: ComponentFactoryResolver, @Inject(PLATFORM_ID) private platformId, ) {} @@ -216,7 +217,8 @@ export class NbPopoverDirective implements OnInit, OnDestroy { * and {@link NbPopoverDirective#adjustment}. * */ private renderPopover() { - this.themeService.appendToLayoutTop(NbPopoverComponent) + const factory = this.componentFactoryResolver.resolveComponentFactory(NbPopoverComponent); + this.themeService.appendToLayoutTop(factory) .pipe(takeWhile(() => this.alive)) .subscribe((containerRef: ComponentRef) => { this.containerRef = containerRef; diff --git a/src/framework/theme/services/theme.service.ts b/src/framework/theme/services/theme.service.ts index 3222a50cfa..ca11910708 100644 --- a/src/framework/theme/services/theme.service.ts +++ b/src/framework/theme/services/theme.service.ts @@ -4,7 +4,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. */ -import { Inject, Injectable, Type } from '@angular/core'; +import { ComponentFactory, ComponentFactoryResolver, Inject, Injectable, Type } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { ReplaySubject } from 'rxjs/ReplaySubject'; @@ -41,6 +41,7 @@ export class NbThemeService { @Inject(nbThemeOptionsToken) protected options: any, private breakpointService: NbMediaBreakpointsService, private jsThemesRegistry: NbJSThemesRegistry, + private componentFactoryResolver: ComponentFactoryResolver, ) { if (options && options.name) { this.changeTheme(options.name); @@ -56,9 +57,15 @@ export class NbThemeService { this.changeWindowWidth$.next(width); } - appendToLayoutTop(component: Type): Observable { + appendToLayoutTop(entity: Type | ComponentFactory): Observable { + let factory = entity; + + if (entity instanceof Type) { + factory = this.componentFactoryResolver.resolveComponentFactory(entity); + } + const subject = new ReplaySubject(1); - this.appendToLayoutTop$.next({ component, listener: subject }); + this.appendToLayoutTop$.next({ factory, listener: subject }); return subject.asObservable(); }