1 import {Component, EventEmitter, OnInit, Input, Output, ViewChildren, QueryList, forwardRef} from '@angular/core';
2 import {ControlValueAccessor, FormGroup, FormControl, NG_VALUE_ACCESSOR} from '@angular/forms';
3 import {AuthService} from '@eg/core/auth.service';
4 import {IdlObject} from '@eg/core/idl.service';
5 import {OrgService} from '@eg/core/org.service';
6 import {OrgSelectComponent} from '@eg/share/org-select/org-select.component';
8 export interface OrgFamily {
10 includeAncestors?: boolean;
11 includeDescendants?: boolean;
16 selector: 'eg-org-family-select',
17 templateUrl: 'org-family-select.component.html',
20 provide: NG_VALUE_ACCESSOR,
21 useExisting: forwardRef(() => OrgFamilySelectComponent),
26 export class OrgFamilySelectComponent implements ControlValueAccessor, OnInit {
28 // The label for this input
29 @Input() labelText = 'Library';
31 // Should the Ancestors checkbox be hidden?
32 @Input() hideAncestorSelector = false;
34 // Should the Descendants checkbox be hidden?
35 @Input() hideDescendantSelector = false;
37 // Should the Ancestors checkbox be checked by default?
39 // Ignored if [hideAncestorSelector]="true"
40 @Input() ancestorSelectorChecked = false;
42 // Should the Descendants checkbox be checked by default?
44 // Ignored if [hideDescendantSelector]="true"
45 @Input() descendantSelectorChecked = false;
48 @Input() selectedOrgId: number;
50 // Only show the OUs that the user has certain permissions at
51 @Input() limitPerms: string[];
53 @Input() domId: string;
55 @Output() onChange = new EventEmitter<any>();
57 @ViewChildren(OrgSelectComponent) orgSelects: QueryList<OrgSelectComponent>;
59 // this is the most up-to-date value used for ngModel and reactive form
63 orgOnChange: ($event: IdlObject) => void;
64 emitArray: () => void;
66 familySelectors: FormGroup;
68 propagateChange = (_: OrgFamily) => {};
69 propagateTouch = () => {};
72 private auth: AuthService,
73 private org: OrgService
78 if (this.selectedOrgId) {
79 this.options = {primaryOrgId: this.selectedOrgId};
80 } else if (this.auth.user()) {
81 this.options = {primaryOrgId: this.auth.user().ws_ou()};
84 this.familySelectors = new FormGroup({
85 'includeAncestors': new FormControl({
86 value: this.ancestorSelectorChecked,
87 disabled: this.disableAncestorSelector()}),
88 'includeDescendants': new FormControl({
89 value: this.descendantSelectorChecked,
90 disabled: this.disableDescendantSelector()}),
94 this.domId = 'org-family-select-' + Math.floor(Math.random() * 100000);
97 this.familySelectors.valueChanges.subscribe(val => {
101 this.orgOnChange = ($event: IdlObject) => {
102 this.options.primaryOrgId = $event.id();
103 this.disableAncestorSelector() ? this.includeAncestors.disable() : this.includeAncestors.enable();
104 this.disableDescendantSelector() ? this.includeDescendants.disable() : this.includeDescendants.enable();
108 this.emitArray = () => {
109 // Prepare and emit an array containing the primary org id and
110 // optionally ancestor and descendant org units, and flags that select those.
112 this.options.orgIds = [this.options.primaryOrgId];
113 this.options.includeAncestors = this.includeAncestors.value;
114 this.options.includeDescendants = this.includeDescendants.value;
116 if (this.includeAncestors.value) {
117 this.options.orgIds = this.org.ancestors(this.options.primaryOrgId, true);
120 if (this.includeDescendants.value) {
121 this.options.orgIds = this.options.orgIds.concat(
122 this.org.descendants(this.options.primaryOrgId, true));
125 // Using ancestors() and descendants() can result in
126 // duplicate org ID's. Be nice and uniqify.
127 const hash: any = {};
128 this.options.orgIds.forEach(id => hash[id] = true);
129 this.options.orgIds = Object.keys(hash).map(id => Number(id));
131 this.propagateChange(this.options);
132 this.onChange.emit(this.options);
136 writeValue(value: OrgFamily) {
138 this.selectedOrgId = value['primaryOrgId'];
139 if (this.orgSelects) {
140 this.orgSelects.toArray()[0].applyOrgId = this.selectedOrgId;
141 this.options = {primaryOrgId: this.selectedOrgId};
143 this.familySelectors.patchValue({
144 'includeAncestors': value['includeAncestors'] ? value['includeAncestors'] : false,
145 'includeDescendants': value['includeDescendants'] ? value['includeDescendants'] : false,
150 registerOnChange(fn) {
151 this.propagateChange = fn;
154 registerOnTouched(fn) {
155 this.propagateTouch = fn;
158 disableAncestorSelector(): boolean {
159 return this.options.primaryOrgId === this.org.root().id();
162 disableDescendantSelector(): boolean {
163 const contextOrg = this.org.get(this.options.primaryOrgId);
164 return contextOrg.children().length === 0;
167 get includeAncestors() {
168 return this.familySelectors.get('includeAncestors');
170 get includeDescendants() {
171 return this.familySelectors.get('includeDescendants');