Skip to content
This repository has been archived by the owner on Dec 8, 2022. It is now read-only.

Commit

Permalink
Implemented the use of the SkyDynamicComponentService (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
Blackbaud-TrevorBurch authored Dec 20, 2018
1 parent ae8b7c1 commit 6ba8717
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 130 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@
"@angular/core": "^4.3.6",
"@angular/forms": "^4.3.6",
"@angular/router": "^4.3.6",
"@skyux/core": "^3.1.0",
"@skyux/core": "^3.5.1",
"@skyux/i18n": "^3.3.0",
"@skyux/indicators": "^3.0.0-rc.1"
},
"dependencies": {},
"devDependencies": {
"@blackbaud/skyux": "2.34.0",
"@blackbaud/skyux": "2.35.0",
"@blackbaud/skyux-builder": "1.30.0",
"@skyux-sdk/builder-plugin-skyux": "1.0.0-rc.5"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ import {
],
imports: [
CommonModule,
NoopAnimationsModule,
RouterTestingModule,
SkyFlyoutModule,
SkyModalModule,
SkyToastModule
SkyToastModule,
NoopAnimationsModule
],
exports: [
SkyFlyoutTestSampleComponent,
Expand Down
11 changes: 0 additions & 11 deletions src/app/public/modules/flyout/flyout-adapter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,6 @@ export class SkyFlyoutAdapterService {
this.renderer = this.rendererFactory.createRenderer(undefined, undefined);
}

public appendToBody(element: any): void {
const body = this.windowRef.getWindow().document.body;
this.renderer.appendChild(body, element);
}

public removeHostElement(): void {
const document = this.windowRef.getWindow().document;
const hostElement = document.querySelector('sky-flyout');
this.renderer.removeChild(document.body, hostElement);
}

public adjustHeaderForHelp(header: ElementRef): void {
const windowObj = this.windowRef.getWindow();
const helpWidget = windowObj.document.getElementById('bb-help-invoker');
Expand Down
2 changes: 2 additions & 0 deletions src/app/public/modules/flyout/flyout.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ describe('Flyout component', () => {
applicationRef.tick();
tick();
fixture.detectChanges();
flyoutService.ngOnDestroy();
applicationRef.tick();
fixture.destroy();
}));

Expand Down
4 changes: 3 additions & 1 deletion src/app/public/modules/flyout/flyout.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from '@angular/router';

import {
SkyDynamicComponentModule,
SkyWindowRefService
} from '@skyux/core';

Expand Down Expand Up @@ -62,7 +63,8 @@ import {
RouterModule,
SkyI18nModule,
SkyIconModule,
SkyFlyoutResourcesModule
SkyFlyoutResourcesModule,
SkyDynamicComponentModule
],
exports: [
SkyFlyoutComponent
Expand Down
154 changes: 63 additions & 91 deletions src/app/public/modules/flyout/flyout.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
import {
ApplicationRef,
ComponentFactoryResolver,
Injector
ApplicationRef
} from '@angular/core';

import {
inject,
TestBed,
tick,
fakeAsync
TestBed
} from '@angular/core/testing';

import {
NoopAnimationsModule
} from '@angular/platform-browser/animations';

import {
expect
} from '@skyux-sdk/testing';

import {
SkyDynamicComponentService,
SkyWindowRefService
} from '@skyux/core';

import {
SkyFlyoutAdapterService
} from './flyout-adapter.service';

import {
SkyFlyoutFixturesModule
} from './fixtures/flyout-fixtures.module';

import {
SkyFlyoutHostsTestComponent
} from './fixtures/flyout-hosts.component.fixture';

import {
SkyFlyoutService
} from './flyout.service';
Expand All @@ -36,107 +37,78 @@ import {
} from './types';

describe('Flyout service', () => {
let service: SkyFlyoutService;
let applicationRef: ApplicationRef;

beforeEach(() => {
TestBed.configureTestingModule({
imports: [
NoopAnimationsModule
SkyFlyoutFixturesModule
],
providers: [
SkyFlyoutService,
{
provide: SkyFlyoutAdapterService,
useValue: {
appendToBody() { },
removeHostElement() { }
}
},
{
provide: ApplicationRef,
useValue: {
attachView() {},
detachView() {}
}
},
Injector,
{
provide: ComponentFactoryResolver,
useValue: {
resolveComponentFactory() {
return {
create() {
return {
destroy() {},
hostView: {
rootNodes: [
{}
]
},
instance: {
messageStream: {
take() {
return {
subscribe() { }
};
},
next() {}
},
attach() {
return {
close() { },
closed: {
take() {
return {
subscribe() { }
};
}
}
};
}
}
};
}
};
}
}
},
SkyFlyoutAdapterService,
SkyWindowRefService
]
});

service = TestBed.get(SkyFlyoutService);
});

it('should only create a single host component', inject(
[SkyFlyoutService],
(service: SkyFlyoutService) => {
beforeEach(
inject(
[
ApplicationRef
],
(
_applicationRef: ApplicationRef
) => {
applicationRef = _applicationRef;
}
)
);

it('should only create a single host component', () => {
const spy = spyOn(service as any, 'createHostComponent').and.callThrough();
service.open({} as any);
service.open({} as any);
service.open(SkyFlyoutHostsTestComponent);
service.open(SkyFlyoutHostsTestComponent);
expect(spy.calls.count()).toEqual(1);
}
));
);

it('should return an instance with a close method', inject(
[SkyFlyoutService],
(service: SkyFlyoutService) => {
const flyout = service.open({} as any);
it('should return an instance with a close method', () => {
const flyout = service.open(SkyFlyoutHostsTestComponent);
expect(typeof flyout.close).toEqual('function');
}
));

it('should expose a method to remove the flyout from the DOM', fakeAsync(inject(
[SkyFlyoutService, SkyFlyoutAdapterService, ApplicationRef],
(
service: SkyFlyoutService,
adapter: SkyFlyoutAdapterService,
appRef: ApplicationRef
) => {
service.open({} as any);
tick();
);

it('should expose a method to remove the flyout from the DOM', () => {
spyOn(window, 'setTimeout').and.callFake((fun: Function) => {
fun();
});
service.open(SkyFlyoutHostsTestComponent);
applicationRef.tick();
const spy = spyOn(service['host'].instance.messageStream, 'next').and.callThrough();
service.close();
tick();
applicationRef.tick();
expect(spy).toHaveBeenCalledWith({
type: SkyFlyoutMessageType.Close
});
}
)));
);

it('should dispose of any open host if the service is destroyed', () => {
spyOn(window, 'setTimeout').and.callFake((fun: Function) => {
fun();
});
service.open(SkyFlyoutHostsTestComponent);
applicationRef.tick();
const dynamicService = TestBed.get(SkyDynamicComponentService);
const spy = spyOn(dynamicService, 'removeComponent').and.callThrough();
// Note: Calling the lifecycle function directly as there is no way to destroy the service
// as it would be in the wild.
service.ngOnDestroy();
applicationRef.tick();
expect(spy).toHaveBeenCalled();
}
);
});
33 changes: 10 additions & 23 deletions src/app/public/modules/flyout/flyout.service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import {
ApplicationRef,
ComponentFactoryResolver,
ComponentRef,
EmbeddedViewRef,
Injectable,
Injector,
Type,
OnDestroy
} from '@angular/core';
Expand All @@ -17,7 +13,8 @@ import {
import 'rxjs/add/operator/take';

import {
SkyWindowRefService
SkyWindowRefService,
SkyDynamicComponentService
} from '@skyux/core';

import {
Expand Down Expand Up @@ -47,14 +44,15 @@ export class SkyFlyoutService implements OnDestroy {

constructor(
private adapter: SkyFlyoutAdapterService,
private appRef: ApplicationRef,
private injector: Injector,
private resolver: ComponentFactoryResolver,
private windowRef: SkyWindowRefService
private windowRef: SkyWindowRefService,
private dynamicComponentService: SkyDynamicComponentService
) { }

public ngOnDestroy(): void {
this.removeListners();
if (this.host) {
this.removeHostComponent();
}
}

public open<T>(component: Type<T>, config?: SkyFlyoutConfig): SkyFlyoutInstance<T> {
Expand Down Expand Up @@ -85,26 +83,15 @@ export class SkyFlyoutService implements OnDestroy {
}

private createHostComponent(): ComponentRef<SkyFlyoutComponent> {
const componentRef = this.resolver
.resolveComponentFactory(SkyFlyoutComponent)
.create(this.injector);

const domElem = (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0];

this.appRef.attachView(componentRef.hostView);
this.adapter.appendToBody(domElem);

return componentRef;
this.host = this.dynamicComponentService.createComponent(SkyFlyoutComponent);
return this.host;
}

private removeHostComponent() {
if (this.host) {
this.appRef.detachView(this.host.hostView);
this.host.destroy();
this.dynamicComponentService.removeComponent(this.host);
this.host = undefined;
}

this.adapter.removeHostElement();
}

private addListeners<T>(flyout: SkyFlyoutInstance<T>): void {
Expand Down

0 comments on commit 6ba8717

Please sign in to comment.