Skip to content

Commit a560e02

Browse files
committed
refactor(grid): add additional files
1 parent e936c4f commit a560e02

13 files changed

+4527
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
import { Injectable } from '@angular/core';
2+
import { Subject } from 'rxjs';
3+
import { cloneArray } from '../core/utils';
4+
import { IFilteringExpression, FilteringLogic } from '../data-operations/filtering-expression.interface';
5+
import { ISortingExpression, SortingDirection } from '../data-operations/sorting-expression.interface';
6+
import { IgxGridCellComponent } from './cell.component';
7+
import { IgxColumnComponent } from './column.component';
8+
import { IgxGridRowComponent } from '../grid/row.component';
9+
import { IFilteringOperation, FilteringExpressionsTree, IFilteringExpressionsTree } from '../../public_api';
10+
import { IGridEditEventArgs, IGridComponent } from './grid-interfaces';
11+
12+
/**
13+
*@hidden
14+
*/
15+
@Injectable()
16+
export abstract class IGridAPIService <T extends IGridComponent> {
17+
18+
public change: Subject<any> = new Subject<any>();
19+
protected state: Map<string, T> = new Map<string, T>();
20+
protected editCellState: Map<string, any> = new Map<string, any>();
21+
protected summaryCacheMap: Map<string, Map<string, any[]>> = new Map<string, Map<string, any[]>>();
22+
23+
public register(grid: IGridComponent) {
24+
this.state.set(grid.id, grid as T);
25+
}
26+
27+
public unsubscribe(grid: IGridComponent) {
28+
this.state.delete(grid.id);
29+
}
30+
31+
public get(id: string): T {
32+
return this.state.get(id);
33+
}
34+
35+
public unset(id: string) {
36+
this.state.delete(id);
37+
this.summaryCacheMap.delete(id);
38+
this.editCellState.delete(id);
39+
}
40+
41+
public get_column_by_name(id: string, name: string): IgxColumnComponent {
42+
return this.get(id).columns.find((col) => col.field === name);
43+
}
44+
45+
public set_summary_by_column_name(id: string, name: string) {
46+
if (!this.summaryCacheMap.get(id)) {
47+
this.summaryCacheMap.set(id, new Map<string, any[]>());
48+
}
49+
const column = this.get_column_by_name(id, name);
50+
if (this.get(id).filteredData && this.get(id).filteredData.length >= 0) {
51+
this.calculateSummaries(id, column, this.get(id).filteredData.map((rec) => rec[column.field]));
52+
} else {
53+
if (this.get(id).data) {
54+
this.calculateSummaries(id, column, this.get(id).data.map((rec) => rec[column.field]));
55+
}
56+
}
57+
}
58+
59+
public get_summaries(id: string) {
60+
return this.summaryCacheMap.get(id);
61+
}
62+
63+
public remove_summary(id: string, name?: string) {
64+
if (this.summaryCacheMap.has(id)) {
65+
if (!name) {
66+
this.summaryCacheMap.delete(id);
67+
} else {
68+
this.summaryCacheMap.get(id).delete(name);
69+
}
70+
}
71+
}
72+
73+
public set_cell_inEditMode(gridId: string, cell, editMode: boolean) {
74+
if (!this.editCellState.has(gridId)) {
75+
this.editCellState.set(gridId, null);
76+
}
77+
if (!this.get_cell_inEditMode(gridId) && editMode) {
78+
this.editCellState.set(gridId, { cellID: cell.cellID, cell: Object.assign({}, cell) });
79+
}
80+
}
81+
82+
public escape_editMode(gridId, cellId?) {
83+
const editableCell = this.get_cell_inEditMode(gridId);
84+
if (editableCell) {
85+
if (cellId) {
86+
if (cellId.rowID === editableCell.cellID.rowID &&
87+
cellId.columnID === editableCell.cellID.columnID) {
88+
this.editCellState.delete(gridId);
89+
}
90+
} else {
91+
this.editCellState.delete(gridId);
92+
}
93+
}
94+
95+
this.refreshSearch(gridId);
96+
}
97+
98+
public get_cell_inEditMode(gridId) {
99+
const editCellId = this.editCellState.get(gridId);
100+
if (editCellId) {
101+
return editCellId;
102+
} else {
103+
return null;
104+
}
105+
106+
}
107+
108+
public get_row_by_key(id: string, rowSelector: any): IgxGridRowComponent {
109+
const primaryKey = this.get(id).primaryKey;
110+
if (primaryKey !== undefined && primaryKey !== null) {
111+
return this.get(id).dataRowList.find((row) => row.rowData[primaryKey] === rowSelector);
112+
} else {
113+
return this.get(id).dataRowList.find((row) => row.rowData === rowSelector);
114+
}
115+
}
116+
117+
public get_row_by_index(id: string, rowIndex: number): IgxGridRowComponent {
118+
return this.get(id).rowList.find((row) => row.index === rowIndex);
119+
}
120+
121+
public get_cell_by_key(id: string, rowSelector: any, field: string): IgxGridCellComponent {
122+
const row = this.get_row_by_key(id, rowSelector);
123+
if (row && row.cells) {
124+
return row.cells.find((cell) => cell.column.field === field);
125+
}
126+
}
127+
128+
public get_cell_by_index(id: string, rowIndex: number, columnIndex: number): IgxGridCellComponent {
129+
const row = this.get_row_by_index(id, rowIndex);
130+
if (row && row.cells) {
131+
return row.cells.find((cell) => cell.columnIndex === columnIndex);
132+
}
133+
}
134+
135+
public get_cell_by_visible_index(id: string, rowIndex: number, columnIndex: number): IgxGridCellComponent {
136+
const row = this.get_row_by_index(id, rowIndex);
137+
if (row && row.cells) {
138+
return row.cells.find((cell) => cell.visibleColumnIndex === columnIndex);
139+
}
140+
}
141+
142+
public submit_value(gridId) {
143+
const editableCell = this.get_cell_inEditMode(gridId);
144+
if (editableCell) {
145+
if (!editableCell.cell.column.inlineEditorTemplate && editableCell.cell.column.dataType === 'number') {
146+
if (!this.get_cell_inEditMode(gridId).cell.editValue) {
147+
this.update_cell(gridId, editableCell.cellID.rowID, editableCell.cellID.columnID, 0);
148+
} else {
149+
const val = parseFloat(this.get_cell_inEditMode(gridId).cell.editValue);
150+
if (!isNaN(val) || isFinite(val)) {
151+
this.update_cell(gridId, editableCell.cellID.rowID, editableCell.cellID.columnID, val);
152+
}
153+
}
154+
} else {
155+
this.update_cell(gridId, editableCell.cellID.rowID, editableCell.cellID.columnID, editableCell.cell.editValue);
156+
}
157+
this.escape_editMode(gridId, editableCell.cellID);
158+
this.get(gridId).cdr.detectChanges();
159+
}
160+
}
161+
162+
public update_cell(id: string, rowID, columnID, editValue) {
163+
let cellObj;
164+
const editableCell = this.get_cell_inEditMode(id);
165+
const row = this.get(id).rowList.find((r) => r.rowID === rowID);
166+
if (editableCell && editableCell.cellID.rowID === rowID && editableCell.cellID.columnID === columnID) {
167+
cellObj = editableCell.cell;
168+
} else if (row) {
169+
cellObj = this.get(id).columns[columnID].cells.find((cell) => cell.cellID.rowID === rowID);
170+
}
171+
if (cellObj) {
172+
const args: IGridEditEventArgs = {
173+
row: cellObj.row, cell: cellObj,
174+
currentValue: cellObj.value, newValue: editValue
175+
};
176+
this.get(id).onEditDone.emit(args);
177+
const column = this.get(id).columns[columnID];
178+
if (this.get(id).primaryKey) {
179+
const index = this.get(id).data.map((record) => record[this.get(id).primaryKey]).indexOf(rowID);
180+
this.get(id).data[index][column.field] = args.newValue;
181+
} else {
182+
this.get(id).data[this.get(id).data.indexOf(rowID)][column.field] = args.newValue;
183+
}
184+
(this.get(id) as any)._pipeTrigger++;
185+
}
186+
}
187+
188+
public update_row(value: any, id: string, row: IgxGridRowComponent): void {
189+
const index = this.get(id).data.indexOf(row.rowData);
190+
const args: IGridEditEventArgs = { row, cell: null, currentValue: this.get(id).data[index], newValue: value };
191+
this.get(id).onEditDone.emit(args);
192+
this.get(id).data[index] = args.newValue;
193+
(this.get(id) as any)._pipeTrigger++;
194+
}
195+
196+
public sort(id: string, fieldName: string, dir: SortingDirection, ignoreCase: boolean): void {
197+
if (dir === SortingDirection.None) {
198+
this.remove_grouping_expression(id, fieldName);
199+
}
200+
const sortingState = cloneArray(this.get(id).sortingExpressions);
201+
202+
this.prepare_sorting_expression([sortingState], { fieldName, dir, ignoreCase });
203+
this.get(id).sortingExpressions = sortingState;
204+
}
205+
206+
public sort_multiple(id: string, expressions: ISortingExpression[]): void {
207+
const sortingState = cloneArray(this.get(id).sortingExpressions);
208+
209+
for (const each of expressions) {
210+
if (each.dir === SortingDirection.None) {
211+
this.remove_grouping_expression(id, each.fieldName);
212+
}
213+
this.prepare_sorting_expression([sortingState], each);
214+
}
215+
216+
this.get(id).sortingExpressions = sortingState;
217+
}
218+
219+
public filter(id: string, fieldName: string, term, conditionOrExpressionsTree: IFilteringOperation | IFilteringExpressionsTree,
220+
ignoreCase: boolean) {
221+
const grid = this.get(id);
222+
const filteringTree = grid.filteringExpressionsTree;
223+
this.escape_editMode(id);
224+
225+
if (grid.paging) {
226+
grid.page = 0;
227+
}
228+
229+
const fieldFilterIndex = filteringTree.findIndex(fieldName);
230+
if (fieldFilterIndex > -1) {
231+
filteringTree.filteringOperands.splice(fieldFilterIndex, 1);
232+
}
233+
234+
this.prepare_filtering_expression(filteringTree, fieldName, term, conditionOrExpressionsTree, ignoreCase);
235+
grid.filteringExpressionsTree = filteringTree;
236+
}
237+
238+
public filter_global(id, term, condition, ignoreCase) {
239+
const grid = this.get(id);
240+
const filteringTree = grid.filteringExpressionsTree;
241+
if (grid.paging) {
242+
grid.page = 0;
243+
}
244+
245+
filteringTree.filteringOperands = [];
246+
this.remove_summary(id);
247+
248+
if (condition) {
249+
for (const column of grid.columns) {
250+
this.prepare_filtering_expression(filteringTree, column.field, term,
251+
condition, ignoreCase || column.filteringIgnoreCase);
252+
}
253+
}
254+
255+
grid.filteringExpressionsTree = filteringTree;
256+
}
257+
258+
public clear_filter(id, fieldName) {
259+
if (fieldName) {
260+
const column = this.get_column_by_name(id, fieldName);
261+
if (!column) {
262+
return;
263+
}
264+
}
265+
266+
const grid = this.get(id);
267+
const filteringState = grid.filteringExpressionsTree;
268+
const index = filteringState.findIndex(fieldName);
269+
270+
if (index > -1) {
271+
filteringState.filteringOperands.splice(index, 1);
272+
this.remove_summary(id, fieldName);
273+
} else {
274+
filteringState.filteringOperands = [];
275+
this.remove_summary(id);
276+
}
277+
278+
grid.filteringExpressionsTree = filteringState;
279+
grid.filteredData = null;
280+
}
281+
282+
protected calculateSummaries(id: string, column, data) {
283+
if (!this.summaryCacheMap.get(id).get(column.field)) {
284+
this.summaryCacheMap.get(id).set(column.field,
285+
column.summaries.operate(data));
286+
}
287+
}
288+
289+
public clear_sort(id, fieldName) {
290+
const sortingState = this.get(id).sortingExpressions;
291+
const index = sortingState.findIndex((expr) => expr.fieldName === fieldName);
292+
if (index > -1) {
293+
sortingState.splice(index, 1);
294+
this.get(id).sortingExpressions = sortingState;
295+
}
296+
}
297+
298+
protected prepare_filtering_expression(filteringState: IFilteringExpressionsTree, fieldName: string, searchVal,
299+
conditionOrExpressionsTree: IFilteringOperation | IFilteringExpressionsTree, ignoreCase: boolean) {
300+
301+
let newExpressionsTree;
302+
const oldExpressionsTreeIndex = filteringState.findIndex(fieldName);
303+
const expressionsTree = conditionOrExpressionsTree instanceof FilteringExpressionsTree ?
304+
conditionOrExpressionsTree as IFilteringExpressionsTree : null;
305+
const condition = conditionOrExpressionsTree instanceof FilteringExpressionsTree ?
306+
null : conditionOrExpressionsTree as IFilteringOperation;
307+
const newExpression: IFilteringExpression = { fieldName, searchVal, condition, ignoreCase };
308+
309+
if (oldExpressionsTreeIndex === -1) {
310+
// no expressions tree found for this field
311+
if (expressionsTree) {
312+
filteringState.filteringOperands.push(expressionsTree);
313+
} else if (condition) {
314+
// create expressions tree for this field and add the new expression to it
315+
newExpressionsTree = new FilteringExpressionsTree(filteringState.operator, fieldName);
316+
newExpressionsTree.filteringOperands.push(newExpression);
317+
filteringState.filteringOperands.push(newExpressionsTree);
318+
}
319+
}
320+
}
321+
322+
protected prepare_sorting_expression(states, expression: ISortingExpression) {
323+
if (expression.dir === SortingDirection.None) {
324+
states.forEach(state => {
325+
state.splice(state.findIndex((expr) => expr.fieldName === expression.fieldName), 1);
326+
});
327+
return;
328+
}
329+
330+
states.forEach(state => {
331+
const e = state.find((expr) => expr.fieldName === expression.fieldName);
332+
if (!e) {
333+
state.push(expression);
334+
} else {
335+
Object.assign(e, expression);
336+
}
337+
});
338+
}
339+
340+
protected abstract remove_grouping_expression(id: string, fieldName: string);
341+
public abstract refreshSearch(id: string, updateHighlight?: boolean);
342+
343+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<ng-template #defaultCell igxTextHighlight [cssClass]="highlightClass" [activeCssClass]="activeHighlightClass" [groupName]="gridID"
2+
[value]="formatter ? formatter(value) : value" [row]="rowIndex" [column]="this.column.visibleIndex" [page]="this.grid.page" [containerClass]="'igx-grid__td-text'">
3+
<div class="igx-grid__td-text">{{ formatter ? formatter(value) : value }}</div>
4+
</ng-template>
5+
<ng-template #inlineEditor let-cell="cell">
6+
<ng-container *ngIf="column.dataType === 'string'">
7+
<igx-input-group>
8+
<input igxInput [(ngModel)]="gridAPI.get_cell_inEditMode(gridID).cell.editValue" [igxFocus]="focused">
9+
</igx-input-group>
10+
</ng-container>
11+
<ng-container *ngIf="column.dataType === 'number'">
12+
<igx-input-group>
13+
<input igxInput [(ngModel)]="gridAPI.get_cell_inEditMode(gridID).cell.editValue" [igxFocus]="focused" type="number">
14+
</igx-input-group>
15+
</ng-container>
16+
<ng-container *ngIf="column.dataType === 'boolean'">
17+
<igx-checkbox [(ngModel)]="gridAPI.get_cell_inEditMode(gridID).cell.editValue" [checked]="gridAPI.get_cell_inEditMode(gridID).cell.editValue" [disableRipple]="true"></igx-checkbox>
18+
</ng-container>
19+
<ng-container *ngIf="column.dataType === 'date'">
20+
<igx-datePicker [(ngModel)]="gridAPI.get_cell_inEditMode(gridID).cell.editValue" (onClose)="focusCell()" [labelVisibility]="false"></igx-datePicker>
21+
</ng-container>
22+
</ng-template>
23+
<ng-container *ngTemplateOutlet="template; context: context">
24+
</ng-container>

0 commit comments

Comments
 (0)