1 /* eslint-disable eqeqeq */
2 import {Component, Input, OnInit, QueryList, ViewChild, ViewChildren} from '@angular/core';
3 import {GridContext, GridColumn} from './grid';
4 import {IdlObject} from '@eg/core/idl.service';
5 import {ComboboxComponent, ComboboxEntry} from '@eg/share/combobox/combobox.component';
6 import {DateSelectComponent} from '@eg/share/date-select/date-select.component';
7 import {OrgSelectComponent} from '@eg/share/org-select/org-select.component';
8 import {OrgService} from '@eg/core/org.service';
9 import {NgbDropdown} from '@ng-bootstrap/ng-bootstrap';
12 selector: 'eg-grid-filter-control',
13 templateUrl: './grid-filter-control.component.html'
16 export class GridFilterControlComponent implements OnInit {
18 @Input() context: GridContext;
19 @Input() col: GridColumn;
22 @ViewChildren(ComboboxComponent) filterComboboxes: QueryList<ComboboxComponent>;
23 @ViewChildren(OrgSelectComponent) orgSelects: QueryList<OrgSelectComponent>;
24 @ViewChildren(NgbDropdown) dropdowns: QueryList<NgbDropdown>;
26 @ViewChild('dateSelectOne') dateSelectOne: DateSelectComponent;
27 @ViewChild('dateSelectTwo') dateSelectTwo: DateSelectComponent;
29 // So we can use (ngModelChange) on the link combobox
30 linkFilterEntry: ComboboxEntry = null;
33 private org: OrgService
37 if (this.col.filterValue !== undefined) {
38 this.applyFilter(this.col);
42 operatorChanged(col: GridColumn) {
43 if (col.filterOperator === 'null' || col.filterOperator === 'not null') {
44 col.filterInputDisabled = true;
45 col.filterValue = undefined;
47 col.filterInputDisabled = false;
51 applyOrgFilter(col: GridColumn) {
52 let org: IdlObject = (col.filterValue as unknown) as IdlObject;
55 this.clearFilter(col);
58 org = this.org.get(org); // if coming from a Named Filter Set, filterValue would be an an org id
59 const ous: any[] = new Array();
60 if (col.filterIncludeOrgDescendants || col.filterIncludeOrgAncestors) {
61 if (col.filterIncludeOrgAncestors) {
62 ous.push(...this.org.ancestors(org, true));
64 if (col.filterIncludeOrgDescendants) {
65 ous.push(...this.org.descendants(org, true));
72 const op: string = (col.filterOperator === '=' ? 'in' : 'not in');
73 filt[col.name][op] = ous;
74 this.context.dataSource.filters[col.name] = [ filt ];
75 col.isFiltered = true;
76 this.context.reload();
81 applyLinkFilter(col: GridColumn) {
82 if (col.filterValue) {
83 this.applyFilter(col);
86 // Value was cleared from the combobox
87 this.clearFilter(col);
91 // TODO: this was copied from date-select and
92 // really belongs in a date service
93 localDateFromYmd(ymd: string): Date {
94 const parts = ymd.split('-');
96 Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
99 /* eslint-disable no-magic-numbers */
100 applyDateFilter(col: GridColumn) {
101 const dateStr = this.dateSelectOne.currentAsYmd();
103 this.dateSelectTwo ? this.dateSelectTwo.currentAsYmd() : null;
105 if (endDateStr && !dateStr) {
106 // User has applied a second date (e.g. between) but cleared
107 // the first date. Avoid applying the filter until
108 // dateStr gets a value or endDateStr is cleared or the
113 if (col.filterOperator === 'null' || col.filterOperator === 'not null') {
114 this.applyFilter(col);
116 if (dateStr == null) {
117 this.clearFilter(col);
120 const date: Date = this.localDateFromYmd(dateStr);
121 let date1 = new Date();
122 let date2 = new Date();
123 const op: string = col.filterOperator;
124 const filt: Object = {};
125 const filt2: Object = {};
126 const filters = new Array();
127 if (col.filterOperator === '>') {
130 date1.setMinutes(59);
131 date1.setSeconds(59);
132 filt[op] = date1.toISOString();
133 if (col.name === 'dob') { filt[op] = dateStr; } // special case
134 filt2[col.name] = filt;
136 } else if (col.filterOperator === '>=') {
138 filt[op] = date1.toISOString();
139 if (col.name === 'dob') { filt[op] = dateStr; } // special case
140 filt2[col.name] = filt;
142 } else if (col.filterOperator === '<') {
144 filt[op] = date1.toISOString();
145 if (col.name === 'dob') { filt[op] = dateStr; } // special case
146 filt2[col.name] = filt;
148 } else if (col.filterOperator === '<=') {
151 date1.setMinutes(59);
152 date1.setSeconds(59);
153 filt[op] = date1.toISOString();
154 if (col.name === 'dob') { filt[op] = dateStr; } // special case
155 filt2[col.name] = filt;
157 } else if (col.filterOperator === '=') {
158 date1 = new Date(date.valueOf());
159 filt['>='] = date1.toISOString();
160 if (col.name === 'dob') { filt['>='] = dateStr; } // special case
161 filt2[col.name] = filt;
164 date2 = new Date(date.valueOf());
166 date2.setMinutes(59);
167 date2.setSeconds(59);
168 const filt_a: Object = {};
169 const filt2_a: Object = {};
170 filt_a['<='] = date2.toISOString();
171 if (col.name === 'dob') { filt_a['<='] = dateStr; } // special case
172 filt2_a[col.name] = filt_a;
173 filters.push(filt2_a);
174 } else if (col.filterOperator === '!=') {
175 date1 = new Date(date.valueOf());
176 filt['<'] = date1.toISOString();
177 if (col.name === 'dob') { filt['<'] = dateStr; } // special case
178 filt2[col.name] = filt;
180 date2 = new Date(date.valueOf());
182 date2.setMinutes(59);
183 date2.setSeconds(59);
184 const filt_a: Object = {};
185 const filt2_a: Object = {};
186 filt_a['>'] = date2.toISOString();
187 if (col.name === 'dob') { filt_a['>'] = dateStr; } // special case
188 filt2_a[col.name] = filt_a;
190 const date_filt: any = { '-or': [] };
191 date_filt['-or'].push(filt2);
192 date_filt['-or'].push(filt2_a);
193 filters.push(date_filt);
194 } else if (col.filterOperator === 'between') {
197 // User has not applied the second date yet.
202 date2 = this.localDateFromYmd(endDateStr);
207 // don't make user care about the order
208 // they enter the dates in
212 filt[date1op] = date1.toISOString();
213 if (col.name === 'dob') { filt['>='] = dateStr; } // special case
214 filt2[col.name] = filt;
218 date2.setMinutes(59);
219 date2.setSeconds(59);
220 const filt_a: Object = {};
221 const filt2_a: Object = {};
222 filt_a[date2op] = date2.toISOString();
223 if (col.name === 'dob') { filt_a['<='] = endDateStr; } // special case
224 filt2_a[col.name] = filt_a;
225 filters.push(filt2_a);
227 this.context.dataSource.filters[col.name] = filters;
228 col.isFiltered = true;
229 this.context.reload();
230 this.closeDropdown();
233 /* eslint-enable no-magic-numbers */
235 clearDateFilter(col: GridColumn) {
236 delete this.context.dataSource.filters[col.name];
237 col.isFiltered = false;
238 this.context.reload();
239 this.closeDropdown();
241 applyBooleanFilter(col: GridColumn) {
242 if (!col.filterValue || col.filterValue === '') {
243 delete this.context.dataSource.filters[col.name];
244 col.isFiltered = false;
245 this.context.reload();
247 const val: string = col.filterValue;
249 const filt: Object = {};
251 const filt2: Object = {};
252 filt2[col.name] = filt;
253 this.context.dataSource.filters[col.name] = [ filt2 ];
254 col.isFiltered = true;
255 this.context.reload();
258 this.closeDropdown();
261 applyFilterCommon(col: GridColumn) {
263 switch (col.datatype) {
266 this.linkFilterEntry ? this.linkFilterEntry.id : null;
267 return this.applyLinkFilter(col);
269 return this.applyBooleanFilter(col);
271 return this.applyDateFilter(col);
273 return this.applyOrgFilter(col);
275 return this.applyFilter(col);
279 applyFilter(col: GridColumn) {
280 // fallback if the operator somehow was not set yet
281 if (col.filterOperator === undefined) { col.filterOperator = '='; }
283 if ( (col.filterOperator !== 'null') && (col.filterOperator !== 'not null') &&
284 (!col.filterValue || col.filterValue === '') &&
285 (col.filterValue !== '0') ) {
286 // if value is empty and we're _not_ checking for null/not null, clear
288 delete this.context.dataSource.filters[col.name];
289 col.isFiltered = false;
291 let op: string = col.filterOperator;
292 let val: string = col.filterValue;
293 if (col.filterOperator === 'null') {
296 } else if (col.filterOperator === 'not null') {
299 } else if (col.filterOperator === 'like' || col.filterOperator === 'not like') {
300 val = '%' + val + '%';
301 } else if (col.filterOperator === 'startswith') {
304 } else if (col.filterOperator === 'endswith') {
308 const filt: any = {};
309 if (col.filterOperator === 'not like') {
311 filt['-not'][col.name] = {};
312 filt['-not'][col.name]['like'] = val;
313 this.context.dataSource.filters[col.name] = [ filt ];
314 col.isFiltered = true;
317 filt[col.name][op] = val;
318 this.context.dataSource.filters[col.name] = [ filt ];
319 col.isFiltered = true;
322 this.context.reload();
323 this.closeDropdown();
325 clearFilter(col: GridColumn) {
326 // clear filter values...
328 // ... and inform the data source
329 delete this.context.dataSource.filters[col.name];
330 col.isFiltered = false;
332 this.context.reload();
333 this.closeDropdown();
337 // Timeout allows actions to occur before closing (some) dropdows
338 // clears the values (e.g. link selector)
339 setTimeout(() => this.dropdowns.forEach(drp => { drp.close(); }));
343 if (this.filterComboboxes) {
344 this.filterComboboxes.forEach(ctl => { ctl.applyEntryId(null); });
346 if (this.orgSelects) {
347 this.orgSelects.forEach(ctl => { ctl.reset(); });
349 if (this.dateSelectOne) { this.dateSelectOne.reset(); }
350 if (this.dateSelectTwo) { this.dateSelectTwo.reset(); }