LP#1775466 Dynamic component continued
authorBill Erickson <berickxx@gmail.com>
Wed, 13 Jun 2018 16:20:43 +0000 (12:20 -0400)
committerBill Erickson <berickxx@gmail.com>
Wed, 5 Sep 2018 14:05:23 +0000 (10:05 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/share/dynamic-component/dynamic.component.ts
Open-ILS/src/eg2/src/app/share/grid/grid.ts
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts

index 5dba7ba..35723a8 100644 (file)
@@ -1,10 +1,13 @@
-import {Component, OnInit, ViewChild, Input} from '@angular/core';
-import {Compiler, ViewContainerRef, NgModule} from '@angular/core';
+import {Component, OnInit, ViewChild, Input, Output} from '@angular/core';
+import {Compiler, ViewContainerRef, NgModule, EventEmitter} 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.
+ * 
+ * Content text or URL values may be provided as Inputs or passed
+ * directly to component build* methods.
  */
 
 @Component({
@@ -17,30 +20,61 @@ export class DynamicComponent implements OnInit {
     @ViewChild('container', {read: ViewContainerRef})
     private container: ViewContainerRef;
 
+    @Input() content: string;
+    @Input() contentUrl: string;
+    @Input() contextData: any;
+
+    // Emits true if the content was render-able, false otherwise
+    @Output() onComplete: EventEmitter<boolean>;
+
     constructor(
         private compiler: Compiler,
         private http: HttpClient
-    ) {}
+    ) {
+        this.onComplete = new EventEmitter<boolean>();
+    }
 
     ngOnInit() {
+        if (this.contentUrl) {
+            this.buildFromUrl(this.contentUrl, this.contextData);
+        } else if (this.content) {
+            this.buildFromString(this.content, this.contextData);
+        }
     }
 
     buildFromString(template: string, context: any = {}) {
-        this.addComponent(template, context);
+        try {
+            this.addComponent(template, context);
+        } catch (err) {
+            console.error(`Error rendering dynamic content: ${err}`);
+            this.onComplete.emit(false);
+            return;
+        }
+
+        this.onComplete.emit(true);
     }
 
     // Returns a promise which resolves if the requested URL
-    // was found, rejected otherwise.
+    // was found and was render-able, rejected otherwise.
     buildFromUrl(url: string, context: any = {}): Promise<void> {
         return this.http.get(url, {responseType: 'text'}).toPromise()
         .then(
             html => {
                 console.debug(`Loaded dynamic content from: ${url}`);
-                this.addComponent(html, context);
+                try {
+                    this.addComponent(html, context);
+                } catch (err) {
+                    const msg = `Error rendering dynamic content: ${url}`;
+                    console.error(msg);
+                    this.onComplete.emit(false);
+                    return Promise.reject(msg);
+                }
+                this.onComplete.emit(true);
             },
             notFound => {
                 console.debug(
                     `Unable to fetch dynamic component URL: ${url}`, notFound);    
+                this.onComplete.emit(false);
             }
         )
     }
index 2c7de9d..480ffe0 100644 (file)
@@ -290,7 +290,7 @@ export class GridContext {
         this.store = store;
         this.format = format;
         this.pager = new Pager();
-        this.pager.limit = 10; // TODO config
+        this.pager.limit = 10;
         this.rowSelector = new GridRowSelector();
         this.toolbarButtons = [];
         this.toolbarActions = [];
@@ -331,7 +331,6 @@ export class GridContext {
         if (this.pageChanges) { return; }
         this.pageChanges = this.pager.onChange$.subscribe(
             val => this.dataSource.requestPage(this.pager));
-        // TODO: index rows as they arrive
     }
 
     ignorePager() {
@@ -393,6 +392,7 @@ export class GridContext {
     getColumnTextContent(row: any, col: GridColumn): string {
         if (col.cellTemplate) {
             // TODO
+            // Extract the text content from the rendered template.
         } else {
             return this.getRowColumnValue(row, col);
         }
index 87fc90d..6fc4afe 100644 (file)
 <b>Dynamic content: </b>
 <eg-dynamic-component #dynamic></eg-dynamic-component>
 
+<br/>
+<!--
 <b>Dynamic content via URL: </b>
 <eg-dynamic-component #dynamicUrl></eg-dynamic-component>
+<br/>
+-->
+
+<b>Dynamic Complent via URL Inline</b>
+<eg-dynamic-component 
+  contentUrl="/test-template.html" 
+  [contextData]="{world:'world'}"
+  (onComplete)="renderLocal=!$event">
+</eg-dynamic-component>
+<div *ngIf="renderLocal">
+  <b>fall through local template: hello {{world}}</b>
+</div>
 
 
 <br/><br/>
index 7ff0ac0..bedadd1 100644 (file)
@@ -36,7 +36,8 @@ export class SandboxComponent implements OnInit {
     gridDataSource: GridDataSource = new GridDataSource();
 
     btSource: GridDataSource = new GridDataSource();
-    btGridTestContext: any = {hello : 'world'};
+    world = 'world'; // for local template version
+    btGridTestContext: any = {hello : this.world};
 
     testDate: any;
 
@@ -72,19 +73,19 @@ export class SandboxComponent implements OnInit {
         };
 
         this.dynamic.buildFromString(
-            '<b>HELLO {{world}}</b>', {world: 'world'});
+            '<b>HELLO {{world}}</b>', {world: this.world});
 
         /*
         // Assumes a file on the server at this URL
         this.dynamicUrl.buildFromUrl(
-            '/test-template.html', {world: 'world'});
+            '/test-template.html', {world: this.world});
         */
     }
 
     doPrint() {
         this.printer.print({
             template: this.printTemplate,
-            contextData: {world : 'world'},
+            contextData: {world : this.world},
             printContext: 'default'
         });
     }