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 @ViewChildren(OrgSelectComponent) orgSelects: QueryList<OrgSelectComponent>;
57 // this is the most up-to-date value used for ngModel and reactive form
61 orgOnChange: ($event: IdlObject) => void;
62 emitArray: () => void;
64 familySelectors: FormGroup;
66 propagateChange = (_: OrgFamily) => {};
67 propagateTouch = () => {};
70 private auth: AuthService,
71 private org: OrgService
76 if (this.selectedOrgId) {
77 this.options = {primaryOrgId: this.selectedOrgId};
78 } else if (this.auth.user()) {
79 this.options = {primaryOrgId: this.auth.user().ws_ou()};
82 this.familySelectors = new FormGroup({
83 'includeAncestors': new FormControl({
84 value: this.ancestorSelectorChecked,
85 disabled: this.disableAncestorSelector()}),
86 'includeDescendants': new FormControl({
87 value: this.descendantSelectorChecked,
88 disabled: this.disableDescendantSelector()}),
92 this.domId = 'org-family-select-' + Math.floor(Math.random() * 100000);
95 this.familySelectors.valueChanges.subscribe(val => {
99 this.orgOnChange = ($event: IdlObject) => {
100 this.options.primaryOrgId = $event.id();
101 this.disableAncestorSelector() ? this.includeAncestors.disable() : this.includeAncestors.enable();
102 this.disableDescendantSelector() ? this.includeDescendants.disable() : this.includeDescendants.enable();
106 this.emitArray = () => {
107 // Prepare and emit an array containing the primary org id and
108 // optionally ancestor and descendant org units.
110 this.options.orgIds = [this.options.primaryOrgId];
112 if (this.includeAncestors.value) {
113 this.options.orgIds = this.org.ancestors(this.options.primaryOrgId, true);
116 if (this.includeDescendants.value) {
117 this.options.orgIds = this.options.orgIds.concat(
118 this.org.descendants(this.options.primaryOrgId, true));
121 // Using ancestors() and descendants() can result in
122 // duplicate org ID's. Be nice and uniqify.
123 const hash: any = {};
124 this.options.orgIds.forEach(id => hash[id] = true);
125 this.options.orgIds = Object.keys(hash).map(id => Number(id));
127 this.propagateChange(this.options);
131 writeValue(value: OrgFamily) {
133 this.selectedOrgId = value['primaryOrgId'];
134 if (this.orgSelects) {
135 this.orgSelects.toArray()[0].applyOrgId = this.selectedOrgId;
136 this.options = {primaryOrgId: this.selectedOrgId};
138 this.familySelectors.patchValue({
139 'includeAncestors': value['includeAncestors'] ? value['includeAncestors'] : false,
140 'includeDescendants': value['includeDescendants'] ? value['includeDescendants'] : false,
145 registerOnChange(fn) {
146 this.propagateChange = fn;
149 registerOnTouched(fn) {
150 this.propagateTouch = fn;
153 disableAncestorSelector(): boolean {
154 return this.options.primaryOrgId === this.org.root().id();
157 disableDescendantSelector(): boolean {
158 const contextOrg = this.org.get(this.options.primaryOrgId);
159 return contextOrg.children().length === 0;
162 get includeAncestors() {
163 return this.familySelectors.get('includeAncestors');
165 get includeDescendants() {
166 return this.familySelectors.get('includeDescendants');