-<style>
- .org-depth-1 { padding-left:3px; }
- .org-depth-2 { padding-left:6px; }
- .org-depth-3 { padding-left:9px; }
- .org-depth-4 { padding-left:12px; }
-</style>
-<div>
- <input type="text"
- class="form-control"
- [placeholder]="placeholder"
- [(ngModel)]="selectedOrg"
- [ngbTypeahead]="orgFilter"
- />
-</div>
+
+<!-- todo disabled -->
+<ng-template #displayTemplate let-r="result">
+{{r.label}}
+</ng-template>
+
+<input type="text"
+ class="form-control"
+ [placeholder]="placeholder"
+ [(ngModel)]="selected"
+ [ngbTypeahead]="filter"
+ [resultTemplate]="displayTemplate"
+ [inputFormatter]="formatter"
+ (selectItem)="orgChanged($event)"
+/>
import {Component, OnInit, Input} from '@angular/core';
import {Observable} from 'rxjs/Observable';
-import {map, tap, debounceTime, distinctUntilChanged} from 'rxjs/operators';
+import {map, debounceTime} from 'rxjs/operators';
import {EgAuthService} from '@eg/core/auth';
import {EgStoreService} from '@eg/core/store';
import {EgOrgService} from '@eg/core/org';
import {EgIdlObject} from '@eg/core/idl';
+import {NgbTypeaheadSelectItemEvent} from '@ng-bootstrap/ng-bootstrap';
+
+// Use a unicode char for spacing instead of ASCII=32 so the browser
+// won't collapse the nested display entries down to a single space.
+const PAD_SPACE: string = ' '; // U+2007
+
+interface OrgDisplay {
+ id: number;
+ label: string;
+ disabled: boolean;
+}
@Component({
selector: 'eg-org-select',
templateUrl: './org-select.component.html'
})
-
export class EgOrgSelectComponent implements OnInit {
+ selected: OrgDisplay;
+
+ // Read-only properties optionally provided by the calling component.
@Input() placeholder: String;
- @Input() selectedOrg: EgIdlObject;
- @Input() displayField: String = 'shortname';
+ @Input() initialOrg: EgIdlObject;
@Input() stickySetting: String;
- @Input() onChange: (org:EgIdlObject) => void;
- @Input() shouldDisable: (org:EgIdlObject) => Boolean;
- @Input() shouldHide: (org:EgIdlObject) => Boolean;
- @Input() allDisabled: Boolean = false;
+ @Input() displayField: String = 'shortname';
- testString: String = '';
+ // Call-backs
+ // Note onChange could be handled via an EventEmitter, but
+ // should* functions require real time two-way communication.
+ @Input() onChange: (org:EgIdlObject) => void;
+ @Input() shouldDisable: (org:EgIdlObject) => boolean;
+ @Input() shouldHide: (org:EgIdlObject) => boolean;
constructor(
private egAuth: EgAuthService,
ngOnInit() {
}
- orgFilter = (text$: Observable<string>): Observable<string[]> => {
+ orgChanged(selEvent: NgbTypeaheadSelectItemEvent) {
+ if (this.onChange) {
+ this.onChange(this.egOrg.get(selEvent.item.id));
+ }
+ }
+
+ // Formats the selected value
+ formatter = (result: OrgDisplay) => result.label.trim();
+
+ filter = (text$: Observable<string>): Observable<OrgDisplay[]> => {
return text$
.debounceTime(100)
.distinctUntilChanged()
.map(term => {
+
+ // TODO: displayField / shortname
return this.egOrg.list().filter(org => {
- let sn = org.shortname().toLowerCase();
- return sn.indexOf(term.toLowerCase()) > -1
+
+ // Find orgs matching the search term
+ return org.shortname()
+ .toLowerCase().indexOf(term.toLowerCase()) > -1
+
+ }).filter(org => {
+ // Exclude hidden orgs
+ return !this.shouldHide || !this.shouldHide(org)
+
}).map(org => {
- // The browser won't collapse multiple spaces when
- // using a space-ish unicode char instead of regular spaces.
- let space = ' '; // U+2007
- let sn = org.shortname();
- for (var i = 0; i < org.ou_type().depth(); i++) {
- sn = space + sn;
+
+ return {
+ id : org.id(),
+ label : PAD_SPACE.repeat(org.ou_type().depth()) + org.shortname(),
+ disabled : this.shouldDisable && this.shouldDisable(org)
}
- return sn;
})
});
}