new Angular file-reader component
authorGalen Charlton <gmc@equinoxinitiative.org>
Fri, 8 Nov 2019 23:39:34 +0000 (18:39 -0500)
committerGalen Charlton <gmc@equinoxinitiative.org>
Mon, 3 Feb 2020 16:58:00 +0000 (11:58 -0500)
This adds a ControlValueAccessor wrapper around a file
reader form input. Any file loaded via that input is interpreted
as a text file whose lines are to be split into an array on
newlines, with leading and trailng whitespace removed.

Usage is:

<eg-file-reader [(ngModel)]="fileContents">
</eg-file-reader>

Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>
Open-ILS/src/eg2/src/app/share/common-widgets.module.ts
Open-ILS/src/eg2/src/app/share/file-reader/file-reader.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/share/file-reader/file-reader.component.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.html
Open-ILS/src/eg2/src/app/staff/sandbox/sandbox.component.ts

index 01b16bd..0f9abd8 100644 (file)
@@ -14,6 +14,7 @@ import {DateSelectComponent} from '@eg/share/date-select/date-select.component';
 import {OrgSelectComponent} from '@eg/share/org-select/org-select.component';
 import {DateRangeSelectComponent} from '@eg/share/daterange-select/daterange-select.component';
 import {DateTimeSelectComponent} from '@eg/share/datetime-select/datetime-select.component';
+import {FileReaderComponent} from '@eg/share/file-reader/file-reader.component';
 
 
 @NgModule({
@@ -24,6 +25,7 @@ import {DateTimeSelectComponent} from '@eg/share/datetime-select/datetime-select
     OrgSelectComponent,
     DateRangeSelectComponent,
     DateTimeSelectComponent,
+    FileReaderComponent,
   ],
   imports: [
     CommonModule,
@@ -43,6 +45,7 @@ import {DateTimeSelectComponent} from '@eg/share/datetime-select/datetime-select
     OrgSelectComponent,
     DateRangeSelectComponent,
     DateTimeSelectComponent,
+    FileReaderComponent,
   ],
 })
 
diff --git a/Open-ILS/src/eg2/src/app/share/file-reader/file-reader.component.html b/Open-ILS/src/eg2/src/app/share/file-reader/file-reader.component.html
new file mode 100644 (file)
index 0000000..d938bf6
--- /dev/null
@@ -0,0 +1 @@
+<input type="file" (change)="changeListener($event)" />
diff --git a/Open-ILS/src/eg2/src/app/share/file-reader/file-reader.component.ts b/Open-ILS/src/eg2/src/app/share/file-reader/file-reader.component.ts
new file mode 100644 (file)
index 0000000..4cbe5de
--- /dev/null
@@ -0,0 +1,62 @@
+/**
+ * <eg-file-reader [(ngModel)]="fileContents">
+ * </eg-file-reader>
+ */
+import {Component, OnInit, Input, Output, ViewChild,
+    TemplateRef, EventEmitter, ElementRef, forwardRef} from '@angular/core';
+import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
+import {Observable, of, Subject} from 'rxjs';
+import {map, tap, reduce, mergeMap, mapTo, debounceTime, distinctUntilChanged, merge, filter} from 'rxjs/operators';
+
+@Component({
+  selector: 'eg-file-reader',
+  templateUrl: './file-reader.component.html',
+  providers: [{
+    provide: NG_VALUE_ACCESSOR,
+    useExisting: forwardRef(() => FileReaderComponent),
+    multi: true
+  }]
+})
+export class FileReaderComponent implements ControlValueAccessor, OnInit {
+
+    // Stub functions required by ControlValueAccessor
+    propagateChange = (_: any) => {};
+    propagateTouch = () => {};
+
+    ngOnInit() {
+    }
+
+    changeListener($event): void {
+        const me = this;
+        if ($event.target.files.length < 1) {
+            return;
+        }
+        const reader = new FileReader();
+        reader.onloadend = function(e) {
+            me.propagateChange(me.parseFileContents(reader.result));
+        };
+        reader.readAsText($event.target.files[0]);
+    }
+
+    parseFileContents(contents): Array<string> {
+        const values = contents.split('\n');
+        values.forEach((val, idx) => {
+            val = val.replace(/\s+$/, '');
+            val = val.replace(/^\s+/, '');
+            values[idx] = val;
+        });
+        return values;
+    }
+
+    writeValue(value: any) {
+        // intentionally empty
+    }
+
+    registerOnChange(fn) {
+        this.propagateChange = fn;
+    }
+
+    registerOnTouched(fn) {
+        this.propagateTouch = fn;
+    }
+}
index 3b9609b..6d88085 100644 (file)
 
 
 <div>
+  <h4>File reader component</h4>
+  <eg-file-reader [(ngModel)]="fileContents"></eg-file-reader>
+  <h5>Contents are:</h5>
+  <ol *ngIf="fileContents && fileContents.length > 0">
+    <li *ngFor="let val of fileContents">{{val}}</li>
+  </ol>
+</div>
+
+<div>
   <h4>Cross-tab communications example</h4>
   <p>To test, open this sandbox in a second browser tab. Enter something in the input box below, then switch to the other tab and click anywhere on the page. 
      You should see the message that you sent to the other browser tab.</p>
index c44a7f7..29b84c9 100644 (file)
@@ -103,6 +103,9 @@ export class SandboxComponent implements OnInit {
     // selector field value on metarecord object
     aMetarecord: string;
 
+    // file-reader example
+    fileContents:  Array<string>;
+
     // cross-tab communications example
     private sbChannel: any;
     sbChannelText: string;