refactor the search form into a separate component
authorGalen Charlton <gmc@equinoxinitiative.org>
Fri, 17 Jan 2020 22:47:42 +0000 (17:47 -0500)
committerGalen Charlton <gmc@equinoxinitiative.org>
Fri, 17 Jan 2020 22:47:42 +0000 (17:47 -0500)
This enables including the form *in* the tab and simplifies
initializing the form during a tab change.

Signed-off-by: Galen Charlton <gmc@equinoxinitiative.org>
13 files changed:
Open-ILS/src/eg2/src/app/staff/acq/search/acq-search-form.component.html [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/acq/search/acq-search-form.component.ts [new file with mode: 0644]
Open-ILS/src/eg2/src/app/staff/acq/search/acq-search.component.html
Open-ILS/src/eg2/src/app/staff/acq/search/acq-search.component.ts
Open-ILS/src/eg2/src/app/staff/acq/search/acq-search.module.ts
Open-ILS/src/eg2/src/app/staff/acq/search/invoice-results.component.html
Open-ILS/src/eg2/src/app/staff/acq/search/invoice-results.component.ts
Open-ILS/src/eg2/src/app/staff/acq/search/lineitem-results.component.html
Open-ILS/src/eg2/src/app/staff/acq/search/lineitem-results.component.ts
Open-ILS/src/eg2/src/app/staff/acq/search/picklist-results.component.html
Open-ILS/src/eg2/src/app/staff/acq/search/picklist-results.component.ts
Open-ILS/src/eg2/src/app/staff/acq/search/purchase-order-results.component.html
Open-ILS/src/eg2/src/app/staff/acq/search/purchase-order-results.component.ts

diff --git a/Open-ILS/src/eg2/src/app/staff/acq/search/acq-search-form.component.html b/Open-ILS/src/eg2/src/app/staff/acq/search/acq-search-form.component.html
new file mode 100644 (file)
index 0000000..14f2e7a
--- /dev/null
@@ -0,0 +1,53 @@
+<div class="row" *ngFor="let t of searchTerms">
+  <div class="col-lg-3">
+    <select class="form-control" id="selected-search-term" [ngModelOptions]="{standalone: true}" [(ngModel)]="t.field"
+      (change)="clearSearchTerm(t)">
+      <option disabled="disabled" i18n>Select Search Field</option>
+      <optgroup *ngFor="let g of hints" label="{{availableSearchFields[g]['__label']}}">
+        <option *ngFor="let o of availableSearchFields[g]['__fields']" value="{{g}}:{{o}}">
+          {{availableSearchFields[g][o].label}}
+        </option>
+      </optgroup>
+    </select>
+  </div>
+  <div class="col-lg-2">
+    <select class="form-control" id="selected-search-op" [ngModelOptions]="{standalone: true}" [(ngModel)]="t.op">
+      <option i18n value="">is</option>
+      <option i18n value="__not">is NOT</option>
+      <option i18n value="__fuzzy" [disabled]="searchTermDatatypes[t.field] != 'text'">contains</option>
+      <option i18n value="__not,__fuzzy" [disabled]="searchTermDatatypes[t.field] != 'text'">does NOT contain</option>
+      <option i18n value="__lte" [disabled]="searchTermDatatypes[t.field] != 'timestamp'">is on or BEFORE</option>
+      <option i18n value="__gte" [disabled]="searchTermDatatypes[t.field] != 'timestamp'">is on or AFTER</option>
+      <option i18n value="__in">matches a term from a file</option>
+    </select>
+  </div>
+  <div class="col-lg-3">
+    <ng-container *ngIf="t.op == '__in'">
+      <eg-file-reader [(ngModel)]="t.value1"></eg-file-reader>
+    </ng-container>
+    <ng-container *ngIf="t.op !== '__in'">
+      <input [(ngModel)]="t.value1" type="text" *ngIf="searchTermDatatypes[t.field] == 'id'" class="form-control" />
+      <input [(ngModel)]="t.value1" type="text" *ngIf="searchTermDatatypes[t.field] == 'text'" class="form-control" />
+      <input [(ngModel)]="t.value1" type="number" *ngIf="searchTermDatatypes[t.field] == 'int'" class="form-control" />
+      <input [(ngModel)]="t.value1" type="number" *ngIf="searchTermDatatypes[t.field] == 'money'" class="form-control" />
+      <eg-org-select *ngIf="searchTermDatatypes[t.field] == 'org_unit'"
+        (onChange)="setOrgUnitSearchValue($event, t)">
+      </eg-org-select>
+      <eg-combobox *ngIf="searchTermDatatypes[t.field] == 'link'"
+        [idlClass]="searchFieldLinkedClasses[t.field]"
+        (onChange)="t.value1 = $event ? $event.id : ''">
+      </eg-combobox>
+      <eg-date-select *ngIf="searchTermDatatypes[t.field] == 'timestamp'"
+        (onChangeAsIso)="t.value1 = $event ? $event : ''; t.is_date = true">
+      </eg-date-select>
+    </ng-container>
+  </div>
+</div>
+<div class="row">
+  <div class="col-lg-2">
+    <button class="form-control" (click)="addSearchTerm()" i18n>Add Search Term</button>
+  </div>
+  <div class="col-lg-2">
+    <button class="form-control btn-success" (click)="submitSearch()" i18n>Search</button>
+  </div>
+</div>
diff --git a/Open-ILS/src/eg2/src/app/staff/acq/search/acq-search-form.component.ts b/Open-ILS/src/eg2/src/app/staff/acq/search/acq-search-form.component.ts
new file mode 100644 (file)
index 0000000..36a50fb
--- /dev/null
@@ -0,0 +1,98 @@
+import {Component, OnInit, AfterViewInit, Output, EventEmitter} from '@angular/core';
+import {NgbTabset, NgbTabChangeEvent} from '@ng-bootstrap/ng-bootstrap';
+import {Router, ActivatedRoute} from '@angular/router';
+import {StaffCommonModule} from '@eg/staff/common.module';
+import {IdlService, IdlObject} from '@eg/core/idl.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {AcqSearchTerm} from './acq-search.service';
+
+@Component({
+  selector: 'eg-acq-search-form',
+  templateUrl: './acq-search-form.component.html'
+})
+
+export class AcqSearchFormComponent implements OnInit, AfterViewInit {
+
+    @Output() searchSubmitted = new EventEmitter<AcqSearchTerm[]>();
+
+    hints = ['jub', 'acqpl', 'acqpo', 'acqinv', 'acqlid'];
+    availableSearchFields = {};
+    searchTermDatatypes = {};
+    searchFieldLinkedClasses = {};
+    validSearchTypes = ['lineitems', 'purchaseorders', 'invoices', 'selectionlists'];
+    defaultSearchType = 'lineitems';
+
+    searchTerms: AcqSearchTerm[] = [];
+
+    constructor(
+        private router: Router,
+        private route: ActivatedRoute,
+        private pcrud: PcrudService,
+        private idl: IdlService,
+    ) {}
+
+    ngOnInit() {
+        const self = this;
+
+        this.hints.forEach(
+            function(hint) {
+                const o = {};
+                o['__label'] = self.idl.classes[hint].label;
+                o['__fields'] = [];
+                self.idl.classes[hint].fields.forEach(
+                    function(field) {
+                        if (!field.virtual) {
+                            o['__fields'].push(field.name);
+                            o[field.name] = {
+                                label: field.label,
+                                datatype: field.datatype
+                            };
+                            self.searchTermDatatypes[hint + ':' + field.name] = field.datatype;
+                            if (field.datatype === 'link') {
+                                self.searchFieldLinkedClasses[hint + ':' + field.name] = field.class;
+                            }
+                        }
+                    }
+                );
+                self.availableSearchFields[hint] = o;
+            }
+        );
+
+        this.hints.push('acqlia');
+        this.availableSearchFields['acqlia'] = {'__label': this.idl.classes.acqlia.label, '__fields': []};
+        this.pcrud.retrieveAll('acqliad', {'order_by': {'acqliad': 'id'}})
+        .subscribe(liad => {
+            this.availableSearchFields['acqlia']['__fields'].push('' + liad.id());
+            this.availableSearchFields['acqlia'][liad.id()] = {
+                label: liad.description(),
+                datatype: 'text'
+            };
+            this.searchTermDatatypes['acqlia:' + liad.id()] = 'text';
+        });
+
+        this.addSearchTerm();
+    }
+
+    ngAfterViewInit() {}
+
+    addSearchTerm() {
+        this.searchTerms.push({ field: '', op: '', value1: '', value2: '' });
+    }
+    clearSearchTerm(term: AcqSearchTerm) {
+        term.value1 = '';
+        term.value2 = '';
+        term.is_date = false;
+    }
+
+    setOrgUnitSearchValue(org: IdlObject, term: AcqSearchTerm) {
+        if (org == null) {
+            term.value1 = '';
+        } else {
+            term.value1 = org.id();
+        }
+    }
+
+    submitSearch() {
+        this.searchSubmitted.emit(this.searchTerms);
+    }
+}
index fb1dc7c..d1d43ee 100644 (file)
@@ -4,61 +4,6 @@
 <div class="row">
   <div class="ml-auto mr-3"><a i18n href="/eg/staff/acq/legacy/search/unified">Legacy Search Interface</a></div>
 </div>
-<div class="row" *ngFor="let t of searchTerms">
-  <div class="col-lg-3">
-    <select class="form-control" id="selected-search-term" [ngModelOptions]="{standalone: true}" [(ngModel)]="t.field"
-      (change)="clearSearchTerm(t)">
-      <option disabled="disabled" i18n>Select Search Field</option>
-      <optgroup *ngFor="let g of hints" label="{{availableSearchFields[g]['__label']}}">
-        <option *ngFor="let o of availableSearchFields[g]['__fields']" value="{{g}}:{{o}}">
-          {{availableSearchFields[g][o].label}}
-        </option>
-      </optgroup>
-    </select>
-  </div>
-  <div class="col-lg-2">
-    <select class="form-control" id="selected-search-op" [ngModelOptions]="{standalone: true}" [(ngModel)]="t.op">
-      <option i18n value="">is</option>
-      <option i18n value="__not">is NOT</option>
-      <option i18n value="__fuzzy" [disabled]="searchTermDatatypes[t.field] != 'text'">contains</option>
-      <option i18n value="__not,__fuzzy" [disabled]="searchTermDatatypes[t.field] != 'text'">does NOT contain</option>
-      <option i18n value="__lte" [disabled]="searchTermDatatypes[t.field] != 'timestamp'">is on or BEFORE</option>
-      <option i18n value="__gte" [disabled]="searchTermDatatypes[t.field] != 'timestamp'">is on or AFTER</option>
-      <option i18n value="__in">matches a term from a file</option>
-    </select>
-  </div>
-  <div class="col-lg-3">
-    <ng-container *ngIf="t.op == '__in'">
-      <eg-file-reader [(ngModel)]="t.value1"></eg-file-reader>
-    </ng-container>
-    <ng-container *ngIf="t.op !== '__in'">
-      <input [(ngModel)]="t.value1" type="text" *ngIf="searchTermDatatypes[t.field] == 'id'" class="form-control" />
-      <input [(ngModel)]="t.value1" type="text" *ngIf="searchTermDatatypes[t.field] == 'text'" class="form-control" />
-      <input [(ngModel)]="t.value1" type="number" *ngIf="searchTermDatatypes[t.field] == 'int'" class="form-control" />
-      <input [(ngModel)]="t.value1" type="number" *ngIf="searchTermDatatypes[t.field] == 'money'" class="form-control" />
-      <eg-org-select *ngIf="searchTermDatatypes[t.field] == 'org_unit'"
-        (onChange)="setOrgUnitSearchValue($event, t)">
-      </eg-org-select>
-      <eg-combobox *ngIf="searchTermDatatypes[t.field] == 'link'"
-        [idlClass]="searchFieldLinkedClasses[t.field]"
-        (onChange)="t.value1 = $event ? $event.id : ''">
-      </eg-combobox>
-      <eg-date-select *ngIf="searchTermDatatypes[t.field] == 'timestamp'"
-        (onChangeAsIso)="t.value1 = $event ? $event : ''; t.is_date = true">
-      </eg-date-select>
-    </ng-container>
-  </div>
-</div>
-<div class="row">
-  <div class="col-lg-2">
-    <button class="form-control" (click)="addSearchTerm()" i18n>Add Search Term</button>
-  </div>
-  <div class="col-lg-2">
-    <button class="form-control btn-success" (click)="submitSearch()" i18n>Search</button>
-  </div>
-</div>
-<div class="row">
-</div>
 <div class="row">
   <div class="col-lg-12">
     <ngb-tabset #acqSearchTabs [activeId]="searchType" (tabChange)="onTabChange($event)" type="pills">
index 2c40c5a..8e3546d 100644 (file)
@@ -16,10 +16,6 @@ import {PicklistResultsComponent} from './picklist-results.component';
 
 export class AcqSearchComponent implements OnInit, AfterViewInit {
 
-    hints = ['jub', 'acqpl', 'acqpo', 'acqinv', 'acqlid'];
-    availableSearchFields = {};
-    searchTermDatatypes = {};
-    searchFieldLinkedClasses = {};
     searchType = '';
     validSearchTypes = ['lineitems', 'purchaseorders', 'invoices', 'selectionlists'];
     defaultSearchType = 'lineitems';
@@ -57,90 +53,11 @@ export class AcqSearchComponent implements OnInit, AfterViewInit {
         this.onTabChange = ($event) => {
             if (this.validSearchTypes.includes($event.nextId)) {
                 this.searchType = $event.nextId;
-                // clear search form upon tab change
-                this.searchTerms = [];
-                this.addSearchTerm();
                 this.router.navigate(['/staff', 'acq', 'search', $event.nextId]);
             }
         };
-
-        this.hints.forEach(
-            function(hint) {
-                const o = {};
-                o['__label'] = self.idl.classes[hint].label;
-                o['__fields'] = [];
-                self.idl.classes[hint].fields.forEach(
-                    function(field) {
-                        if (!field.virtual) {
-                            o['__fields'].push(field.name);
-                            o[field.name] = {
-                                label: field.label,
-                                datatype: field.datatype
-                            };
-                            self.searchTermDatatypes[hint + ':' + field.name] = field.datatype;
-                            if (field.datatype === 'link') {
-                                self.searchFieldLinkedClasses[hint + ':' + field.name] = field.class;
-                            }
-                        }
-                    }
-                );
-                self.availableSearchFields[hint] = o;
-            }
-        );
-
-        this.hints.push('acqlia');
-        this.availableSearchFields['acqlia'] = {'__label': this.idl.classes.acqlia.label, '__fields': []};
-        this.pcrud.retrieveAll('acqliad', {'order_by': {'acqliad': 'id'}})
-        .subscribe(liad => {
-            this.availableSearchFields['acqlia']['__fields'].push('' + liad.id());
-            this.availableSearchFields['acqlia'][liad.id()] = {
-                label: liad.description(),
-                datatype: 'text'
-            };
-            this.searchTermDatatypes['acqlia:' + liad.id()] = 'text';
-        });
-
-        this.addSearchTerm();
     }
 
     ngAfterViewInit() {}
 
-    addSearchTerm() {
-        this.searchTerms.push({ field: '', op: '', value1: '', value2: '' });
-    }
-    clearSearchTerm(term: AcqSearchTerm) {
-        term.value1 = '';
-        term.value2 = '';
-        term.is_date = false;
-    }
-
-    setOrgUnitSearchValue(org: IdlObject, term: AcqSearchTerm) {
-        if (org == null) {
-            term.value1 = '';
-        } else {
-            term.value1 = org.id();
-        }
-    }
-
-    submitSearch() {
-        switch (this.searchType) {
-            case 'lineitems': {
-                this.liResults.forEach(results => results.doSearch(this.searchTerms));
-                break;
-            }
-            case 'purchaseorders': {
-                this.poResults.forEach(results => results.doSearch(this.searchTerms));
-                break;
-            }
-            case 'invoices': {
-                this.invResults.forEach(results => results.doSearch(this.searchTerms));
-                break;
-            }
-            case 'selectionlists': {
-                this.plResults.forEach(results => results.doSearch(this.searchTerms));
-                break;
-            }
-        }
-    }
-
 }
index 47124a4..4dc2251 100644 (file)
@@ -2,6 +2,7 @@ import {NgModule} from '@angular/core';
 import {StaffCommonModule} from '@eg/staff/common.module';
 import {AcqSearchRoutingModule} from './routing.module';
 import {AcqSearchComponent} from './acq-search.component';
+import {AcqSearchFormComponent} from './acq-search-form.component';
 import {LineitemResultsComponent} from './lineitem-results.component';
 import {PurchaseOrderResultsComponent} from './purchase-order-results.component';
 import {InvoiceResultsComponent} from './invoice-results.component';
@@ -14,6 +15,7 @@ import {PicklistMergeDialogComponent} from './picklist-merge-dialog.component';
 @NgModule({
   declarations: [
     AcqSearchComponent,
+    AcqSearchFormComponent,
     LineitemResultsComponent,
     PurchaseOrderResultsComponent,
     InvoiceResultsComponent,
index 2bd346b..cb15329 100644 (file)
@@ -1,3 +1,5 @@
+<eg-acq-search-form (searchSubmitted)="doSearch($event)"></eg-acq-search-form>
+
 <ng-template #inv_identTmpl let-invoice="row">
   <a href="/eg/staff/acq/legacy/invoice/view/{{invoice.id()}}"
      target="_blank">
index 195f899..e3396d6 100644 (file)
@@ -12,6 +12,7 @@ import {AuthService} from '@eg/core/auth.service';
 import {GridComponent} from '@eg/share/grid/grid.component';
 import {GridDataSource} from '@eg/share/grid/grid';
 import {AcqSearchService, AcqSearchTerm} from './acq-search.service';
+import {AcqSearchFormComponent} from './acq-search-form.component';
 
 @Component({
   selector: 'eg-invoice-results',
index f3a6416..e1b222f 100644 (file)
@@ -1,3 +1,5 @@
+<eg-acq-search-form (searchSubmitted)="doSearch($event)"></eg-acq-search-form>
+
 <ng-template #idTmpl let-lineitem="row">
   <a *ngIf="lineitem.purchase_order()" href="/eg/staff/acq/legacy/po/view/{{lineitem.purchase_order()}}?focus_li={{lineitem.id()}}"
      target="_blank">
index 9f2e55d..1a61196 100644 (file)
@@ -9,6 +9,7 @@ import {AuthService} from '@eg/core/auth.service';
 import {GridComponent} from '@eg/share/grid/grid.component';
 import {GridDataSource} from '@eg/share/grid/grid';
 import {AcqSearchService, AcqSearchTerm} from './acq-search.service';
+import {AcqSearchFormComponent} from './acq-search-form.component';
 
 @Component({
   selector: 'eg-lineitem-results',
index 9742653..4d9cdc9 100644 (file)
@@ -1,3 +1,5 @@
+<eg-acq-search-form (searchSubmitted)="doSearch($event)"></eg-acq-search-form>
+
 <eg-string #createSelectionListString i18n-text text="Selection List Created">
 </eg-string>
 <eg-string #cloneSelectionListString i18n-text text="Selection List Cloned">
index c13d838..7745486 100644 (file)
@@ -16,6 +16,7 @@ import {PicklistCreateDialogComponent} from './picklist-create-dialog.component'
 import {PicklistCloneDialogComponent} from './picklist-clone-dialog.component';
 import {PicklistDeleteDialogComponent} from './picklist-delete-dialog.component';
 import {PicklistMergeDialogComponent} from './picklist-merge-dialog.component';
+import {AcqSearchFormComponent} from './acq-search-form.component';
 
 @Component({
   selector: 'eg-picklist-results',
index 5393ffa..4ceda8a 100644 (file)
@@ -1,3 +1,5 @@
+<eg-acq-search-form (searchSubmitted)="doSearch($event)"></eg-acq-search-form>
+
 <ng-template #nameTmpl let-purchaseorder="row">
   <a href="/eg/staff/acq/legacy/po/view/{{purchaseorder.id()}}"
      target="_blank">
index 9c9725f..5861da6 100644 (file)
@@ -9,6 +9,7 @@ import {AuthService} from '@eg/core/auth.service';
 import {GridComponent} from '@eg/share/grid/grid.component';
 import {GridDataSource} from '@eg/share/grid/grid';
 import {AcqSearchService, AcqSearchTerm} from './acq-search.service';
+import {AcqSearchFormComponent} from './acq-search-form.component';
 
 @Component({
   selector: 'eg-purchase-order-results',