• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IgniteUI / igniteui-angular / 13331632524

14 Feb 2025 02:51PM CUT coverage: 22.015% (-69.6%) from 91.622%
13331632524

Pull #15372

github

web-flow
Merge d52d57714 into bcb78ae0a
Pull Request #15372: chore(*): test ci passing

1990 of 15592 branches covered (12.76%)

431 of 964 new or added lines in 18 files covered. (44.71%)

19956 existing lines in 307 files now uncovered.

6452 of 29307 relevant lines covered (22.02%)

249.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.7
/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-api.service.ts
1
import { GridBaseAPIService } from '../api.service';
2
import { GridColumnDataType, DataUtil } from '../../data-operations/data-util';
3
import { ITreeGridRecord } from './tree-grid.interfaces';
4
import { HierarchicalTransaction, TransactionType, State } from '../../services/public_api';
5
import { Injectable } from '@angular/core';
6
import { cloneArray, mergeObjects } from '../../core/utils';
7
import { IFilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree';
8
import { TreeGridFilteringStrategy } from './tree-grid.filtering.strategy';
9
import { ColumnType, GridType } from '../common/grid.interface';
10
import { ISortingExpression } from '../../data-operations/sorting-strategy';
11
import { IgxDataRecordSorting } from '../common/strategy';
12
import { FilterUtil } from '../../data-operations/filtering-strategy';
13

14
@Injectable()
15
export class IgxTreeGridAPIService extends GridBaseAPIService<GridType> {
2✔
16

17
    public override get_all_data(transactions?: boolean): any[] {
UNCOV
18
        const grid = this.grid;
×
UNCOV
19
        let data = grid && grid.flatData ? grid.flatData : [];
×
UNCOV
20
        data = transactions ? grid.dataWithAddedInTransactionRows : data;
×
UNCOV
21
        return data;
×
22
    }
23

24
    public override get_summary_data() {
UNCOV
25
        const grid = this.grid;
×
UNCOV
26
        const data = grid.processedRootRecords?.filter(row => row.isFilteredOutParent === undefined || row.isFilteredOutParent === false)
×
UNCOV
27
            .map(rec => rec.data);
×
UNCOV
28
        if (data && grid.transactions.enabled) {
×
UNCOV
29
            const deletedRows = grid.transactions.getTransactionLog().filter(t => t.type === TransactionType.DELETE).map(t => t.id);
×
UNCOV
30
            deletedRows.forEach(rowID => {
×
UNCOV
31
                const tempData = grid.primaryKey ? data.map(rec => rec[grid.primaryKey]) : data;
×
UNCOV
32
                const index = tempData.indexOf(rowID);
×
UNCOV
33
                if (index !== -1) {
×
UNCOV
34
                    data.splice(index, 1);
×
35
                }
36
            });
37
        }
UNCOV
38
        return data;
×
39
    }
40

41
    public override allow_expansion_state_change(rowID, expanded): boolean {
UNCOV
42
        const grid = this.grid;
×
UNCOV
43
        const row = grid.records.get(rowID);
×
UNCOV
44
        if (row.expanded === expanded ||
×
45
            ((!row.children || !row.children.length) && (!grid.loadChildrenOnDemand ||
46
                (grid.hasChildrenKey && !row.data[grid.hasChildrenKey])))) {
UNCOV
47
            return false;
×
48
        }
UNCOV
49
        return true;
×
50
    }
51

52
    public expand_path_to_record(record: ITreeGridRecord) {
UNCOV
53
        const grid = this.grid;
×
UNCOV
54
        const expandedStates = grid.expansionStates;
×
55

UNCOV
56
        while (record.parent) {
×
UNCOV
57
            record = record.parent;
×
UNCOV
58
            const expanded = this.get_row_expansion_state(record);
×
59

UNCOV
60
            if (!expanded) {
×
UNCOV
61
                expandedStates.set(record.key, true);
×
62
            }
63
        }
UNCOV
64
        grid.expansionStates = expandedStates;
×
65

UNCOV
66
        if (grid.rowEditable) {
×
UNCOV
67
            grid.gridAPI.crudService.endEdit(false);
×
68
        }
69
    }
70

71
    public override get_row_expansion_state(record: ITreeGridRecord): boolean {
UNCOV
72
        const grid = this.grid;
×
UNCOV
73
        const states = grid.expansionStates;
×
UNCOV
74
        const expanded = states.get(record.key);
×
75

UNCOV
76
        if (expanded !== undefined) {
×
UNCOV
77
            return expanded;
×
78
        } else {
UNCOV
79
            return record.children && record.children.length && record.level < grid.expansionDepth;
×
80
        }
81
    }
82

83
    public override should_apply_number_style(column: ColumnType): boolean {
84
        return column.dataType === GridColumnDataType.Number && column.visibleIndex !== 0;
×
85
    }
86

87
    public override deleteRowById(rowID: any): any {
UNCOV
88
        const treeGrid = this.grid;
×
89
        const flatDataWithCascadeOnDeleteAndTransactions =
UNCOV
90
            treeGrid.primaryKey &&
×
91
            treeGrid.foreignKey &&
92
            treeGrid.cascadeOnDelete &&
93
            treeGrid.transactions.enabled;
94

UNCOV
95
        if (flatDataWithCascadeOnDeleteAndTransactions) {
×
UNCOV
96
            treeGrid.transactions.startPending();
×
97
        }
98

UNCOV
99
        const record = super.deleteRowById(rowID);
×
100

UNCOV
101
        if (flatDataWithCascadeOnDeleteAndTransactions) {
×
UNCOV
102
            treeGrid.transactions.endPending(true);
×
103
        }
104

UNCOV
105
        return record;
×
106
    }
107

108
    public override deleteRowFromData(rowID: any, index: number) {
UNCOV
109
        const treeGrid = this.grid;
×
UNCOV
110
        const record = treeGrid.records.get(rowID);
×
111

UNCOV
112
        if (treeGrid.primaryKey && treeGrid.foreignKey) {
×
UNCOV
113
            index = treeGrid.primaryKey ?
×
UNCOV
114
                treeGrid.data.map(c => c[treeGrid.primaryKey]).indexOf(rowID) :
×
115
                treeGrid.data.indexOf(rowID);
UNCOV
116
            super.deleteRowFromData(rowID, index);
×
117

UNCOV
118
            if (treeGrid.cascadeOnDelete) {
×
UNCOV
119
                if (record && record.children) {
×
UNCOV
120
                    for (const child of record.children) {
×
UNCOV
121
                        super.deleteRowById(child.key);
×
122
                    }
123
                }
124
            }
125
        } else {
UNCOV
126
            const collection = record.parent ? record.parent.data[treeGrid.childDataKey] : treeGrid.data;
×
UNCOV
127
            index = treeGrid.primaryKey ?
×
UNCOV
128
                collection.map(c => c[treeGrid.primaryKey]).indexOf(rowID) :
×
129
                collection.indexOf(rowID);
130

UNCOV
131
            const selectedChildren = [];
×
UNCOV
132
            this.get_selected_children(record, selectedChildren);
×
UNCOV
133
            if (selectedChildren.length > 0) {
×
UNCOV
134
                treeGrid.deselectRows(selectedChildren);
×
135
            }
136

UNCOV
137
            if (treeGrid.transactions.enabled) {
×
UNCOV
138
                const path = treeGrid.generateRowPath(rowID);
×
UNCOV
139
                treeGrid.transactions.add({
×
140
                    id: rowID,
141
                    type: TransactionType.DELETE,
142
                    newValue: null,
143
                    path
144
                } as HierarchicalTransaction,
145
                    collection[index]
146
                );
147
            } else {
UNCOV
148
                collection.splice(index, 1);
×
149
            }
UNCOV
150
            this.grid.validation.clear(rowID);
×
151
        }
152
    }
153

154
    public get_selected_children(record: ITreeGridRecord, selectedRowIDs: any[]) {
UNCOV
155
        const grid = this.grid;
×
UNCOV
156
        if (!record.children || record.children.length === 0) {
×
UNCOV
157
            return;
×
158
        }
UNCOV
159
        for (const child of record.children) {
×
UNCOV
160
            if (grid.selectionService.isRowSelected(child.key)) {
×
UNCOV
161
                selectedRowIDs.push(child.key);
×
162
            }
UNCOV
163
            this.get_selected_children(child, selectedRowIDs);
×
164
        }
165
    }
166

167
    public override row_deleted_transaction(rowID: any): boolean {
UNCOV
168
        return this.row_deleted_parent(rowID) || super.row_deleted_transaction(rowID);
×
169
    }
170

171
    public override get_rec_by_id(rowID) {
UNCOV
172
        return this.grid.records.get(rowID);
×
173
    }
174

175
    /**
176
     * Returns the index of the record in the data view by pk or -1 if not found or primaryKey is not set.
177
     *
178
     * @param pk
179
     * @param dataCollection
180
     */
181
    public override get_rec_index_by_id(pk: string | number, dataCollection?: any[]): number {
UNCOV
182
        dataCollection = dataCollection || this.grid.data;
×
UNCOV
183
        return this.grid.primaryKey ? dataCollection.findIndex(rec => rec.data[this.grid.primaryKey] === pk) : -1;
×
184
    }
185

186
    public override addRowToData(data: any, parentRowID?: any) {
UNCOV
187
        if (parentRowID !== undefined && parentRowID !== null) {
×
188

UNCOV
189
            const state = this.grid.transactions.getState(parentRowID);
×
190
            // we should not allow adding of rows as child of deleted row
UNCOV
191
            if (state && state.type === TransactionType.DELETE) {
×
UNCOV
192
                throw Error(`Cannot add child row to deleted parent row`);
×
193
            }
194

UNCOV
195
            const parentRecord = this.grid.records.get(parentRowID);
×
196

UNCOV
197
            if (!parentRecord) {
×
UNCOV
198
                throw Error('Invalid parent row ID!');
×
199
            }
UNCOV
200
            this.grid.summaryService.clearSummaryCache({ rowID: parentRecord.key });
×
UNCOV
201
            if (this.grid.primaryKey && this.grid.foreignKey) {
×
UNCOV
202
                data[this.grid.foreignKey] = parentRowID;
×
UNCOV
203
                super.addRowToData(data);
×
204
            } else {
UNCOV
205
                const parentData = parentRecord.data;
×
UNCOV
206
                const childKey = this.grid.childDataKey;
×
UNCOV
207
                if (this.grid.transactions.enabled) {
×
UNCOV
208
                    const rowId = this.grid.primaryKey ? data[this.grid.primaryKey] : data;
×
UNCOV
209
                    const path: any[] = [];
×
UNCOV
210
                    path.push(...this.grid.generateRowPath(parentRowID));
×
UNCOV
211
                    path.push(parentRowID);
×
UNCOV
212
                    this.grid.transactions.add({
×
213
                        id: rowId,
214
                        path,
215
                        newValue: data,
216
                        type: TransactionType.ADD
217
                    } as HierarchicalTransaction,
218
                        null);
219
                } else {
UNCOV
220
                    if (!parentData[childKey]) {
×
UNCOV
221
                        parentData[childKey] = [];
×
222
                    }
UNCOV
223
                    parentData[childKey].push(data);
×
224
                }
225
            }
226
        } else {
UNCOV
227
            super.addRowToData(data);
×
228
        }
229
    }
230

231
    public override filterDataByExpressions(expressionsTree: IFilteringExpressionsTree): any[] {
UNCOV
232
        const records = this.filterTreeDataByExpressions(expressionsTree);
×
UNCOV
233
        const data = [];
×
234

UNCOV
235
        this.getFlatDataFromFilteredRecords(records, data);
×
236

UNCOV
237
        return data;
×
238
    }
239

240
    public override sortDataByExpressions(data: ITreeGridRecord[], expressions: ISortingExpression[]) {
UNCOV
241
        const records: ITreeGridRecord[] = DataUtil.sort(
×
242
            cloneArray(data),
243
            expressions,
244
            this.grid.sortStrategy ?? new IgxDataRecordSorting(),
×
245
            this.grid);
UNCOV
246
        return records.map(r => r.data);
×
247
    }
248

249
    public filterTreeDataByExpressions(expressionsTree: IFilteringExpressionsTree): ITreeGridRecord[] {
UNCOV
250
        let records = this.grid.rootRecords;
×
251

UNCOV
252
        if (expressionsTree.filteringOperands.length) {
×
253
            const state = {
×
254
                expressionsTree,
255
                strategy: this.grid.filterStrategy ?? new TreeGridFilteringStrategy()
×
256
            };
257
            records = FilterUtil.filter(cloneArray(records), state, this.grid);
×
258
        }
259

UNCOV
260
        return records;
×
261
    }
262

263
    protected override update_row_in_array(value: any, rowID: any, index: number) {
264
        const grid = this.grid;
×
265
        if (grid.primaryKey && grid.foreignKey) {
×
266
            super.update_row_in_array(value, rowID, index);
×
267
        } else {
268
            const record = grid.records.get(rowID);
×
269
            const childData = record.parent ? record.parent.data[grid.childDataKey] : grid.data;
×
270
            index = grid.primaryKey ? childData.map(c => c[grid.primaryKey]).indexOf(rowID) :
×
271
                childData.indexOf(rowID);
272
            childData[index] = value;
×
273
        }
274
    }
275

276
    /**
277
     * Updates related row of provided grid's data source with provided new row value
278
     *
279
     * @param grid Grid to update data for
280
     * @param rowID ID of the row to update
281
     * @param rowValueInDataSource Initial value of the row as it is in data source
282
     * @param rowCurrentValue Current value of the row as it is with applied previous transactions
283
     * @param rowNewValue New value of the row
284
     */
285
    protected override updateData(
286
        grid: GridType,
287
        rowID: any,
288
        rowValueInDataSource: any,
289
        rowCurrentValue: any,
290
        rowNewValue: { [x: string]: any }) {
UNCOV
291
        if (grid.transactions.enabled) {
×
UNCOV
292
            const path = grid.generateRowPath(rowID);
×
UNCOV
293
            const transaction: HierarchicalTransaction = {
×
294
                id: rowID,
295
                type: TransactionType.UPDATE,
296
                newValue: rowNewValue,
297
                path
298
            };
UNCOV
299
            grid.transactions.add(transaction, rowCurrentValue);
×
300
        } else {
UNCOV
301
            mergeObjects(rowValueInDataSource, rowNewValue);
×
302
        }
303
    }
304

305
    private row_deleted_parent(rowID: any): boolean {
UNCOV
306
        const grid = this.grid;
×
UNCOV
307
        if (!grid) {
×
308
            return false;
×
309
        }
UNCOV
310
        if ((grid.cascadeOnDelete && grid.foreignKey) || grid.childDataKey) {
×
UNCOV
311
            let node = grid.records.get(rowID);
×
UNCOV
312
            while (node) {
×
UNCOV
313
                const state: State = grid.transactions.getState(node.key);
×
UNCOV
314
                if (state && state.type === TransactionType.DELETE) {
×
UNCOV
315
                    return true;
×
316
                }
UNCOV
317
                node = node.parent;
×
318
            }
319
        }
UNCOV
320
        return false;
×
321
    }
322

323
    private getFlatDataFromFilteredRecords(records: ITreeGridRecord[], data: any[]) {
UNCOV
324
        if (!records || records.length === 0) {
×
UNCOV
325
            return;
×
326
        }
327

UNCOV
328
        for (const record of records) {
×
UNCOV
329
            if (!record.isFilteredOutParent) {
×
UNCOV
330
                data.push(record);
×
331
            }
UNCOV
332
            this.getFlatDataFromFilteredRecords(record.children, data);
×
333
        }
334
    }
335
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc