From 728e3aee5dea0802b57f100370f9646594d4695e Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Wed, 13 Jun 2018 10:56:30 -0400 Subject: [PATCH] LP#1775466 Dynamic component via string/url support Signed-off-by: Bill Erickson --- .../share/dynamic-component/dynamic.component.ts | 69 ++++++++++++++++++++++ Open-ILS/src/eg2/src/app/staff/common.module.ts | 10 +++- .../src/app/staff/sandbox/sandbox.component.html | 11 ++++ .../eg2/src/app/staff/sandbox/sandbox.component.ts | 14 +++++ 4 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 Open-ILS/src/eg2/src/app/share/dynamic-component/dynamic.component.ts diff --git a/Open-ILS/src/eg2/src/app/share/dynamic-component/dynamic.component.ts b/Open-ILS/src/eg2/src/app/share/dynamic-component/dynamic.component.ts new file mode 100644 index 0000000000..5dba7baa90 --- /dev/null +++ b/Open-ILS/src/eg2/src/app/share/dynamic-component/dynamic.component.ts @@ -0,0 +1,69 @@ +import {Component, OnInit, ViewChild, Input} from '@angular/core'; +import {Compiler, ViewContainerRef, NgModule} from '@angular/core'; +import {HttpClient} from '@angular/common/http'; + +/** + * Render HTML content derived from a string or a URL path, + * interpolating the provided context data along the way. + */ + +@Component({ + selector: 'eg-dynamic-component', + template: '' +}) + +export class DynamicComponent implements OnInit { + + @ViewChild('container', {read: ViewContainerRef}) + private container: ViewContainerRef; + + constructor( + private compiler: Compiler, + private http: HttpClient + ) {} + + ngOnInit() { + } + + buildFromString(template: string, context: any = {}) { + this.addComponent(template, context); + } + + // Returns a promise which resolves if the requested URL + // was found, rejected otherwise. + buildFromUrl(url: string, context: any = {}): Promise { + return this.http.get(url, {responseType: 'text'}).toPromise() + .then( + html => { + console.debug(`Loaded dynamic content from: ${url}`); + this.addComponent(html, context); + }, + notFound => { + console.debug( + `Unable to fetch dynamic component URL: ${url}`, notFound); + } + ) + } + + // Method below taken practically verbatim from + // https://stackoverflow.com/a/39507831 + private addComponent(template: string, context: any) { + @Component({template}) class TemplateComponent {} + @NgModule({declarations: [TemplateComponent]}) class TemplateModule {} + + const mod = + this.compiler.compileModuleAndAllComponentsSync(TemplateModule); + + const factory = mod.componentFactories.find((comp) => + comp.componentType === TemplateComponent + ); + + const component = this.container.createComponent(factory); + Object.assign(component.instance, context); + // If context changes at a later stage, the change detection + // may need to be triggered manually: + // component.changeDetectorRef.detectChanges(); + } + +} + diff --git a/Open-ILS/src/eg2/src/app/staff/common.module.ts b/Open-ILS/src/eg2/src/app/staff/common.module.ts index 2dfbb3cd8f..60d23d6ede 100644 --- a/Open-ILS/src/eg2/src/app/staff/common.module.ts +++ b/Open-ILS/src/eg2/src/app/staff/common.module.ts @@ -1,4 +1,5 @@ import {NgModule, ModuleWithProviders} from '@angular/core'; +import {HttpClientModule} from '@angular/common/http'; import {EgCommonModule} from '@eg/common.module'; import {StaffBannerComponent} from './share/staff-banner.component'; import {OrgSelectComponent} from '@eg/share/org-select/org-select.component'; @@ -12,6 +13,7 @@ import {StringComponent} from '@eg/share/string/string.component'; import {StringService} from '@eg/share/string/string.service'; import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component'; import {DateSelectComponent} from '@eg/share/date-select/date-select.component'; +import {DynamicComponent} from '@eg/share/dynamic-component/dynamic.component'; /** * Imports the EG common modules and adds modules common to all staff UI's. @@ -27,12 +29,15 @@ import {DateSelectComponent} from '@eg/share/date-select/date-select.component'; StringComponent, OpChangeComponent, FmRecordEditorComponent, - DateSelectComponent + DateSelectComponent, + DynamicComponent ], imports: [ + HttpClientModule, EgCommonModule ], exports: [ + HttpClientModule, EgCommonModule, StaffBannerComponent, OrgSelectComponent, @@ -42,7 +47,8 @@ import {DateSelectComponent} from '@eg/share/date-select/date-select.component'; StringComponent, OpChangeComponent, FmRecordEditorComponent, - DateSelectComponent + DateSelectComponent, + DynamicComponent ] }) diff --git a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html index bc6a8d672f..87fc90decf 100644 --- a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html +++ b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html @@ -72,6 +72,17 @@ Hello, {{context.world}}! +

+ + +Dynamic content: + + +Dynamic content via URL: + + + +

diff --git a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts index 11cf154dc0..7ff0ac072e 100644 --- a/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts +++ b/Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts @@ -12,6 +12,7 @@ import {PcrudService} from '@eg/core/pcrud.service'; import {Pager} from '@eg/share/util/pager'; import {DateSelectComponent} from '@eg/share/date-select/date-select.component'; import {PrintService} from '@eg/share/print/print.service'; +import {DynamicComponent} from '@eg/share/dynamic-component/dynamic.component'; @Component({ templateUrl: 'sandbox.component.html' @@ -27,6 +28,9 @@ export class SandboxComponent implements OnInit { @ViewChild('printTemplate') private printTemplate: TemplateRef; + @ViewChild('dynamic') private dynamic: DynamicComponent; + @ViewChild('dynamicUrl') private dynamicUrl: DynamicComponent; + // @ViewChild('helloStr') private helloStr: StringComponent; gridDataSource: GridDataSource = new GridDataSource(); @@ -66,6 +70,15 @@ export class SandboxComponent implements OnInit { order_by: {cbt: 'name'} }); }; + + this.dynamic.buildFromString( + 'HELLO {{world}}', {world: 'world'}); + + /* + // Assumes a file on the server at this URL + this.dynamicUrl.buildFromUrl( + '/test-template.html', {world: 'world'}); + */ } doPrint() { @@ -111,3 +124,4 @@ export class SandboxComponent implements OnInit { } } + -- 2.11.0