1 import {Component, Input, OnInit, QueryList, ViewChildren} from '@angular/core';
2 import {GridContext, GridColumn} from './grid';
3 import {IdlObject} from '@eg/core/idl.service';
4 import {ComboboxComponent} from '@eg/share/combobox/combobox.component';
5 import {DateSelectComponent} from '@eg/share/date-select/date-select.component';
6 import {OrgSelectComponent} from '@eg/share/org-select/org-select.component';
7 import {OrgService} from '@eg/core/org.service';
8 import {NgbDropdown} from '@ng-bootstrap/ng-bootstrap';
11 selector: 'eg-grid-filter-control',
12 templateUrl: './grid-filter-control.component.html'
15 export class GridFilterControlComponent implements OnInit {
17 @Input() context: GridContext;
18 @Input() col: GridColumn;
21 @ViewChildren(ComboboxComponent) filterComboboxes: QueryList<ComboboxComponent>;
22 @ViewChildren(DateSelectComponent) dateSelects: QueryList<DateSelectComponent>;
23 @ViewChildren(OrgSelectComponent) orgSelects: QueryList<OrgSelectComponent>;
24 @ViewChildren(NgbDropdown) dropdowns: QueryList<NgbDropdown>;
27 private org: OrgService
32 operatorChanged(col: GridColumn) {
33 if (col.filterOperator === 'null' || col.filterOperator === 'not null') {
34 col.filterInputDisabled = true;
35 col.filterValue = undefined;
37 col.filterInputDisabled = false;
41 applyOrgFilter(org: IdlObject, col: GridColumn) {
43 this.clearFilter(col);
46 const ous: any[] = new Array();
47 if (col.filterIncludeOrgDescendants || col.filterIncludeOrgAncestors) {
48 if (col.filterIncludeOrgAncestors) {
49 ous.push(...this.org.ancestors(org, true));
51 if (col.filterIncludeOrgDescendants) {
52 ous.push(...this.org.descendants(org, true));
59 const op: string = (col.filterOperator === '=' ? 'in' : 'not in');
60 filt[col.name][op] = ous;
61 this.context.dataSource.filters[col.name] = [ filt ];
62 col.isFiltered = true;
63 this.context.reload();
66 applyLinkFilter($event, col: GridColumn) {
68 col.filterValue = $event.id;
69 this.applyFilter(col);
72 // Value was cleared from the combobox
73 this.clearFilter(col);
77 // TODO: this was copied from date-select and
78 // really belongs in a date service
79 localDateFromYmd(ymd: string): Date {
80 const parts = ymd.split('-');
82 Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
84 applyDateFilter(dateStr: string, col: GridColumn, endDateStr: string) {
85 if (col.filterOperator === 'null' || col.filterOperator === 'not null') {
86 this.applyFilter(col);
88 if (dateStr == null) {
89 this.clearFilter(col);
92 const date: Date = this.localDateFromYmd(dateStr);
93 let date1 = new Date();
94 let date2 = new Date();
95 const op: string = col.filterOperator;
96 const filt: Object = {};
97 const filt2: Object = {};
98 const filters = new Array();
99 if (col.filterOperator === '>') {
102 date1.setMinutes(59);
103 date1.setSeconds(59);
104 filt[op] = date1.toISOString();
105 if (col.name === 'dob') { filt[op] = dateStr; } // special case
106 filt2[col.name] = filt;
108 } else if (col.filterOperator === '>=') {
110 filt[op] = date1.toISOString();
111 if (col.name === 'dob') { filt[op] = dateStr; } // special case
112 filt2[col.name] = filt;
114 } else if (col.filterOperator === '<') {
116 filt[op] = date1.toISOString();
117 if (col.name === 'dob') { filt[op] = dateStr; } // special case
118 filt2[col.name] = filt;
120 } else if (col.filterOperator === '<=') {
123 date1.setMinutes(59);
124 date1.setSeconds(59);
125 filt[op] = date1.toISOString();
126 if (col.name === 'dob') { filt[op] = dateStr; } // special case
127 filt2[col.name] = filt;
129 } else if (col.filterOperator === '=') {
130 date1 = new Date(date.valueOf());
131 filt['>='] = date1.toISOString();
132 if (col.name === 'dob') { filt['>='] = dateStr; } // special case
133 filt2[col.name] = filt;
136 date2 = new Date(date.valueOf());
138 date2.setMinutes(59);
139 date2.setSeconds(59);
140 const filt_a: Object = {};
141 const filt2_a: Object = {};
142 filt_a['<='] = date2.toISOString();
143 if (col.name === 'dob') { filt_a['<='] = dateStr; } // special case
144 filt2_a[col.name] = filt_a;
145 filters.push(filt2_a);
146 } else if (col.filterOperator === '!=') {
147 date1 = new Date(date.valueOf());
148 filt['<'] = date1.toISOString();
149 if (col.name === 'dob') { filt['<'] = dateStr; } // special case
150 filt2[col.name] = filt;
152 date2 = new Date(date.valueOf());
154 date2.setMinutes(59);
155 date2.setSeconds(59);
156 const filt_a: Object = {};
157 const filt2_a: Object = {};
158 filt_a['>'] = date2.toISOString();
159 if (col.name === 'dob') { filt_a['>'] = dateStr; } // special case
160 filt2_a[col.name] = filt_a;
162 const date_filt: any = { '-or': [] };
163 date_filt['-or'].push(filt2);
164 date_filt['-or'].push(filt2_a);
165 filters.push(date_filt);
166 } else if (col.filterOperator === 'between') {
169 // User has not applied the second date yet.
174 date2 = this.localDateFromYmd(endDateStr);
179 // don't make user care about the order
180 // they enter the dates in
184 filt[date1op] = date1.toISOString();
185 if (col.name === 'dob') { filt['>='] = dateStr; } // special case
186 filt2[col.name] = filt;
190 date2.setMinutes(59);
191 date2.setSeconds(59);
192 const filt_a: Object = {};
193 const filt2_a: Object = {};
194 filt_a[date2op] = date2.toISOString();
195 if (col.name === 'dob') { filt_a['<='] = endDateStr; } // special case
196 filt2_a[col.name] = filt_a;
197 filters.push(filt2_a);
199 this.context.dataSource.filters[col.name] = filters;
200 col.isFiltered = true;
201 this.context.reload();
204 // The date filter has autoClose=false so that interacting with
205 // date selectors won't result in closing the dropdown. Once
206 // we've successfully applied a filter, force it closed.
207 this.closeDropdown();
209 clearDateFilter(col: GridColumn) {
210 delete this.context.dataSource.filters[col.name];
211 col.isFiltered = false;
212 this.context.reload();
214 applyBooleanFilter(col: GridColumn) {
215 if (!col.filterValue || col.filterValue === '') {
216 delete this.context.dataSource.filters[col.name];
217 col.isFiltered = false;
218 this.context.reload();
220 const val: string = col.filterValue;
222 const filt: Object = {};
224 const filt2: Object = {};
225 filt2[col.name] = filt;
226 this.context.dataSource.filters[col.name] = [ filt2 ];
227 col.isFiltered = true;
228 this.context.reload();
231 applyFilter(col: GridColumn) {
232 // fallback if the operator somehow was not set yet
233 if (col.filterOperator === undefined) { col.filterOperator = '='; }
235 if ( (col.filterOperator !== 'null') && (col.filterOperator !== 'not null') &&
236 (!col.filterValue || col.filterValue === '') &&
237 (col.filterValue !== '0') ) {
238 // if value is empty and we're _not_ checking for null/not null, clear
240 delete this.context.dataSource.filters[col.name];
241 col.isFiltered = false;
243 let op: string = col.filterOperator;
244 let val: string = col.filterValue;
245 if (col.filterOperator === 'null') {
248 } else if (col.filterOperator === 'not null') {
251 } else if (col.filterOperator === 'like' || col.filterOperator === 'not like') {
252 val = '%' + val + '%';
253 } else if (col.filterOperator === 'startswith') {
256 } else if (col.filterOperator === 'endswith') {
260 const filt: any = {};
261 if (col.filterOperator === 'not like') {
263 filt['-not'][col.name] = {};
264 filt['-not'][col.name]['like'] = val;
265 this.context.dataSource.filters[col.name] = [ filt ];
266 col.isFiltered = true;
269 filt[col.name][op] = val;
270 this.context.dataSource.filters[col.name] = [ filt ];
271 col.isFiltered = true;
274 this.context.reload();
276 clearFilter(col: GridColumn) {
277 // clear filter values...
279 // ... and inform the data source
280 delete this.context.dataSource.filters[col.name];
281 col.isFiltered = false;
283 this.context.reload();
287 this.dropdowns.forEach(drp => { drp.close(); });
291 this.filterComboboxes.forEach(ctl => { ctl.applyEntryId(null); });
292 this.dateSelects.forEach(ctl => { ctl.reset(); });
293 this.orgSelects.forEach(ctl => { ctl.reset(); });