LP1837260 FM Record editor 'inline' display mode
authorBill Erickson <berickxx@gmail.com>
Fri, 19 Jul 2019 21:58:19 +0000 (17:58 -0400)
committerGalen Charlton <gmc@equinoxinitiative.org>
Thu, 1 Aug 2019 20:56:21 +0000 (16:56 -0400)
Adds support for a new @Input() attribute called "displayMode", which
defaults to "dialog".  When the value is set to "inline", the editor
pane will be rendered inline within the page where the
<eg-fm-record-editor/> element resides.

Adds support for success/fail toasts.

Implements the handlers for the previously defined onSave$, onError$,
and onCancel$ EventEmitters, primarly so callers can interact with the
editor in "inline" mode where no "close()" operation occurs.

Sandbox example included.

Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Kyle Huckins <khuckins@catalyte.io>
Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>
Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.html
Open-ILS/src/eg2/src/app/share/fm-editor/fm-editor.component.ts
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html

index ad0c0b7..fc11eee 100644 (file)
@@ -1,13 +1,18 @@
 <!-- idlObject and fieldName applied programmatically -->
 <eg-translate #translator></eg-translate>
 
+<eg-string #successStr text="Update Succeeded" i18n-text></eg-string>
+<eg-string #failStr text="Update Failed" i18n-text></eg-string>
+
 <ng-template #dialogContent>
   <div class="modal-header bg-info">
     <h4 class="modal-title" i18n>Record Editor: {{recordLabel}}</h4>
-    <button type="button" class="close" 
-      i18n-aria-label aria-label="Close" (click)="close()">
-      <span aria-hidden="true">&times;</span>
-    </button>
+    <ng-container *ngIf="isDialog()">
+      <button type="button" class="close" 
+        i18n-aria-label aria-label="Close" (click)="close()">
+        <span aria-hidden="true">&times;</span>
+      </button>
+    </ng-container>
   </div>
   <div class="modal-body">
     <form #fmEditForm="ngForm" role="form" class="form-validated common-form striped-odd">
     </form>
   </div>
   <div class="modal-footer">
-    <button type="button" class="btn btn-success" *ngIf="mode == 'view'"
-      (click)="close()" i18n>Close</button>
+    <ng-container *ngIf="isDialog()">
+      <button type="button" class="btn btn-success" *ngIf="mode == 'view'"
+        (click)="close()" i18n>Close</button>
+      <button type="button" class="btn btn-warning ml-2" *ngIf="mode != 'view'"
+        (click)="cancel()" i18n>Cancel</button>
+    </ng-container>
     <button type="button" class="btn btn-info" 
       [disabled]="fmEditForm.invalid" *ngIf="mode != 'view'"
       (click)="save()" i18n>Save</button>
-    <button type="button" class="btn btn-warning ml-2" *ngIf="mode != 'view'"
-      (click)="cancel()" i18n>Cancel</button>
   </div>
 </ng-template>
+
+<ng-container *ngIf="!isDialog()">
+  <!-- in "inline" mode, render the editor pane right here -->
+  <ng-container *ngTemplateOutlet="dialogContent">
+  </ng-container>
+</ng-container>
+
index f25839b..a574e54 100644 (file)
@@ -6,6 +6,8 @@ import {map} from 'rxjs/operators';
 import {AuthService} from '@eg/core/auth.service';
 import {PcrudService} from '@eg/core/pcrud.service';
 import {DialogComponent} from '@eg/share/dialog/dialog.component';
+import {ToastService} from '@eg/share/toast/toast.service';
+import {StringComponent} from '@eg/share/string/string.component';
 import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
 import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
 import {TranslateComponent} from '@eg/staff/share/translate/translate.component';
@@ -80,10 +82,6 @@ export class FmRecordEditorComponent
     // IDL class hint (e.g. "aou")
     @Input() idlClass: string;
 
-    // mode: 'create' for creating a new record,
-    //       'update' for editing an existing record
-    //       'view' for viewing an existing record without editing
-    mode: 'create' | 'update' | 'view' = 'create';
     recId: any;
 
     // IDL record we are editing
@@ -122,6 +120,9 @@ export class FmRecordEditorComponent
     // for all combobox fields.  See also FmFieldOptions.
     @Input() preloadLinkedValues: boolean;
 
+    // Display within a modal dialog window or inline in the page.
+    @Input() displayMode: 'dialog' | 'inline' = 'dialog';
+
     // Emit the modified object when the save action completes.
     @Output() onSave$ = new EventEmitter<IdlObject>();
 
@@ -132,6 +133,8 @@ export class FmRecordEditorComponent
     @Output() onError$ = new EventEmitter<string>();
 
     @ViewChild('translator') private translator: TranslateComponent;
+    @ViewChild('successStr') successStr: StringComponent;
+    @ViewChild('failStr') failStr: StringComponent;
 
     // IDL info for the the selected IDL class
     idlDef: any;
@@ -146,9 +149,10 @@ export class FmRecordEditorComponent
     // DOM id prefix to prevent id collisions.
     idPrefix: string;
 
-    @Input() editMode(mode: 'create' | 'update' | 'view') {
-        this.mode = mode;
-    }
+    // mode: 'create' for creating a new record,
+    //       'update' for editing an existing record
+    //       'view' for viewing an existing record without editing
+    @Input() mode: 'create' | 'update' | 'view' = 'create';
 
     // Record ID to view/update.  Value is dynamic.  Records are not
     // fetched until .open() is called.
@@ -160,6 +164,7 @@ export class FmRecordEditorComponent
       private modal: NgbModal, // required for passing to parent
       private idl: IdlService,
       private auth: AuthService,
+      private toast: ToastService,
       private pcrud: PcrudService) {
       super(modal);
     }
@@ -174,7 +179,15 @@ export class FmRecordEditorComponent
         // Add some randomness to the generated DOM IDs to ensure against clobbering
         this.idPrefix = 'fm-editor-' + Math.floor(Math.random() * 100000);
 
-        this.onOpen$.subscribe(() => this.initRecord());
+        if (this.isDialog()) {
+            this.onOpen$.subscribe(() => this.initRecord());
+        } else {
+            this.initRecord();
+        }
+    }
+
+    isDialog(): boolean {
+        return this.displayMode === 'dialog';
     }
 
     // Set the record value and clear the recId value to
@@ -460,12 +473,21 @@ export class FmRecordEditorComponent
         const recToSave = this.idl.clone(this.record);
         this.convertDatatypesToIdl(recToSave);
         this.pcrud[this.mode]([recToSave]).toPromise().then(
-            result => this.close(result),
-            error  => this.error(error)
+            result => {
+                this.onSave$.emit(result);
+                this.successStr.current().then(msg => this.toast.success(msg));
+                if (this.isDialog()) { this.close(result); }
+            },
+            error => {
+                this.onError$.emit(error);
+                this.failStr.current().then(msg => this.toast.warning(msg));
+                if (this.isDialog()) { this.error(error); }
+            }
         );
     }
 
     cancel() {
+        this.onCancel$.emit(this.record);
         this.close();
     }
 
index 4ac22a9..2febd8e 100644 (file)
   </div>
 </div>
 
+<div class="mt-4 mb-4">
+  <h4>Inline FM Editor</h4>
+  <div class="row">
+    <div class="col-lg-6">
+      <eg-fm-record-editor displayMode="inline"
+        idlClass="cbt" mode="update" recordId="1" orgDefaultAllowed="owner">
+      </eg-fm-record-editor>
+    </div>
+  </div>
+</div>