Skip to content

Commit a8f6555

Browse files
authored
Merge pull request #10434 from IgniteUI/mevtimov/fix-10018-master
Tree-Grid update cascade selection when filtering is applied
2 parents 4e01d2d + 97b7ec5 commit a8f6555

File tree

4 files changed

+279
-7
lines changed

4 files changed

+279
-7
lines changed

projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-selection.spec.ts

Lines changed: 184 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { TestBed, fakeAsync, tick, waitForAsync } from '@angular/core/testing';
22
import { SortingDirection } from '../../data-operations/sorting-expression.interface';
33
import { IgxTreeGridComponent } from './tree-grid.component';
44
import { IgxGridCell, IgxTreeGridModule } from './public_api';
5-
import { IgxTreeGridCellComponent } from './tree-cell.component';
65
import {
76
IgxTreeGridSimpleComponent,
87
IgxTreeGridCellSelectionComponent,
@@ -11,7 +10,8 @@ import {
1110
IgxTreeGridRowEditingTransactionComponent,
1211
IgxTreeGridCustomRowSelectorsComponent,
1312
IgxTreeGridCascadingSelectionComponent,
14-
IgxTreeGridCascadingSelectionTransactionComponent
13+
IgxTreeGridCascadingSelectionTransactionComponent,
14+
IgxTreeGridPrimaryForeignKeyCascadeSelectionComponent
1515
} from '../../test-utils/tree-grid-components.spec';
1616
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
1717
import {
@@ -53,7 +53,8 @@ describe('IgxTreeGrid - Selection #tGrid', () => {
5353
IgxTreeGridRowEditingTransactionComponent,
5454
IgxTreeGridCustomRowSelectorsComponent,
5555
IgxTreeGridCascadingSelectionComponent,
56-
IgxTreeGridCascadingSelectionTransactionComponent
56+
IgxTreeGridCascadingSelectionTransactionComponent,
57+
IgxTreeGridPrimaryForeignKeyCascadeSelectionComponent
5758
],
5859
imports: [IgxTreeGridModule, NoopAnimationsModule, IgxGridSelectionModule, IgxActionStripModule]
5960
})
@@ -1040,7 +1041,7 @@ describe('IgxTreeGrid - Selection #tGrid', () => {
10401041
}));
10411042
});
10421043

1043-
describe('Cascading Row Selection', () => {
1044+
describe('Cascading Row Selection - Child collection data', () => {
10441045
beforeEach(fakeAsync(() => {
10451046
fix = TestBed.createComponent(IgxTreeGridCascadingSelectionComponent);
10461047
fix.detectChanges();
@@ -1755,6 +1756,185 @@ describe('IgxTreeGrid - Selection #tGrid', () => {
17551756
});
17561757
});
17571758

1759+
describe('Cascading Row Selection - Primary/Foreign key data', () => {
1760+
beforeEach(fakeAsync(() => {
1761+
fix = TestBed.createComponent(IgxTreeGridPrimaryForeignKeyCascadeSelectionComponent);
1762+
fix.detectChanges();
1763+
treeGrid = fix.componentInstance.treeGrid;
1764+
actionStrip = fix.componentInstance.actionStrip;
1765+
}));
1766+
1767+
it(`Filter out all children for a certain parent, except for one. Select it.
1768+
Parent should also become selected. Clear filters. Parent should become in
1769+
indeterminate state as there are non-selected children.`, async () => {
1770+
treeGrid.filter('ID', 475, IgxNumberFilteringOperand.instance().condition('equals'));
1771+
await wait(100);
1772+
fix.detectChanges();
1773+
1774+
treeGrid.selectRows([475], true);
1775+
await wait(100);
1776+
fix.detectChanges();
1777+
1778+
expect(getVisibleSelectedRows(fix).length).toBe(2);
1779+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, true, true);
1780+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 1, true, true);
1781+
1782+
treeGrid.clearFilter();
1783+
await wait(100);
1784+
fix.detectChanges();
1785+
1786+
expect(getVisibleSelectedRows(fix).length).toBe(1);
1787+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null);
1788+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 1, true, true);
1789+
});
1790+
1791+
it(`If there is only one selected leaf row for a particular parent and we filter it out parent's checkbox state -> non-selected.
1792+
All non-direct parents’ checkbox states should be set correctly as well`, async () => {
1793+
treeGrid.selectRows([711], true);
1794+
fix.detectChanges();
1795+
1796+
expect(getVisibleSelectedRows(fix).length).toBe(1);
1797+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null);
1798+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null);
1799+
1800+
treeGrid.filter('ID', 711, IgxNumberFilteringOperand.instance().condition('doesNotEqual'));
1801+
fix.detectChanges();
1802+
1803+
await wait(100);
1804+
fix.detectChanges();
1805+
1806+
expect(getVisibleSelectedRows(fix).length).toBe(0);
1807+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false);
1808+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, false);
1809+
});
1810+
1811+
it(`If there is only one non-selected row for a particular parent and we filter it out parent's checkbox state -> selected.
1812+
All non-direct parents’ checkbox states should be set correctly as well`, async () => {
1813+
treeGrid.selectRows([711, 998], true);
1814+
fix.detectChanges();
1815+
1816+
expect(getVisibleSelectedRows(fix).length).toBe(2);
1817+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null);
1818+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null);
1819+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, true, true);
1820+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 5, true, true);
1821+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 6, false, false);
1822+
1823+
treeGrid.filter('ID', 299, IgxNumberFilteringOperand.instance().condition('doesNotEqual'));
1824+
fix.detectChanges();
1825+
1826+
await wait(200);
1827+
fix.detectChanges();
1828+
1829+
expect(getVisibleSelectedRows(fix).length).toBe(3);
1830+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null);
1831+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true);
1832+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, true, true);
1833+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 5, true, true);
1834+
});
1835+
1836+
it('After adding a new child row to a selected parent its checkbox state SHOULD be indeterminate.', async () => {
1837+
treeGrid.selectRows([847], true);
1838+
fix.detectChanges();
1839+
expect(getVisibleSelectedRows(fix).length).toBe(2);
1840+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 8, true, true);
1841+
TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null);
1842+
1843+
const row = treeGrid.gridAPI.get_row_by_index(8);
1844+
actionStrip.show(row);
1845+
fix.detectChanges();
1846+
1847+
// add new child through the UI
1848+
const editActions = fix.debugElement.queryAll(By.css(`igx-grid-action-button`));
1849+
const addChildBtn = editActions[2].componentInstance;
1850+
addChildBtn.actionClick.emit();
1851+
fix.detectChanges();
1852+
endTransition();
1853+
1854+
const addRow = treeGrid.gridAPI.get_row_by_index(9);
1855+
expect(addRow.addRowUI).toBeTrue();
1856+
1857+
treeGrid.gridAPI.crudService.endEdit(true);
1858+
await wait(100);
1859+
fix.detectChanges();
1860+
const addedRow = treeGrid.gridAPI.get_row_by_index(10);
1861+
expect(addedRow.rowData.Name).toBe(undefined);
1862+
1863+
TreeGridFunctions.verifyDataRowsSelection(fix, [9], true);
1864+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 8, false, null);
1865+
TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null);
1866+
});
1867+
1868+
it('If parent and its children are selected and we delete a child, parent SHOULD be still selected.', async () => {
1869+
treeGrid.selectRows([147], true);
1870+
fix.detectChanges();
1871+
expect(getVisibleSelectedRows(fix).length).toBe(7);
1872+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, true, true);
1873+
TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null);
1874+
1875+
expect(treeGrid.dataRowList.length).toBe(10);
1876+
1877+
const childRow = treeGrid.gridAPI.get_row_by_index(5);
1878+
actionStrip.show(childRow);
1879+
fix.detectChanges();
1880+
1881+
// delete the child through the UI
1882+
const editActions = fix.debugElement.queryAll(By.css(`igx-grid-action-button`));
1883+
const deleteBtn = editActions[2].componentInstance;
1884+
deleteBtn.actionClick.emit();
1885+
fix.detectChanges();
1886+
1887+
await wait(100);
1888+
fix.detectChanges();
1889+
1890+
expect(treeGrid.dataRowList.length).toBe(9);
1891+
expect(getVisibleSelectedRows(fix).length).toBe(6);
1892+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true);
1893+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, true, true);
1894+
TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null);
1895+
});
1896+
1897+
it('If we delete the only selected child of a parent row, the parent checkbox state SHOULD be deselected', async () => {
1898+
treeGrid.selectRows([711], true);
1899+
fix.detectChanges();
1900+
expect(getVisibleSelectedRows(fix).length).toBe(1);
1901+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, null);
1902+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null);
1903+
TreeGridFunctions.verifyHeaderCheckboxSelection(fix, null);
1904+
1905+
expect(treeGrid.dataRowList.length).toBe(10);
1906+
1907+
// delete the child through the API
1908+
const childRow = treeGrid.gridAPI.get_row_by_index(4);
1909+
childRow.delete();
1910+
fix.detectChanges();
1911+
1912+
await wait(100);
1913+
fix.detectChanges();
1914+
1915+
expect(treeGrid.dataRowList.length).toBe(9);
1916+
expect(getVisibleSelectedRows(fix).length).toBe(0);
1917+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, false, false);
1918+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, false);
1919+
TreeGridFunctions.verifyHeaderCheckboxSelection(fix, false);
1920+
});
1921+
1922+
it(`Set nested child row, that has its own children, as initially selected and verify
1923+
that both direct and indirect parent's checkboxes are set in the correct state.`, fakeAsync(() => {
1924+
treeGrid.selectedRows = [317];
1925+
fix.detectChanges();
1926+
tick(100);
1927+
fix.detectChanges();
1928+
1929+
expect(getVisibleSelectedRows(fix).length).toBe(4);
1930+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 0, false, null);
1931+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 3, true, true);
1932+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 4, true, true);
1933+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 5, true, true);
1934+
TreeGridFunctions.verifyRowByIndexSelectionAndCheckboxState(fix, 6, true, true);
1935+
}));
1936+
});
1937+
17581938
describe('Cascading Row Selection with Transaction', () => {
17591939
beforeEach(fakeAsync(() => {
17601940
fix = TestBed.createComponent(IgxTreeGridCascadingSelectionTransactionComponent);

projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ export class IgxTreeGridComponent extends IgxGridBaseDirective implements GridTy
477477
// if a row has been added and before commiting the transaction deleted
478478
const leafRowsDirectParents = new Set<any>();
479479
this.records.forEach(record => {
480-
if (record && !record.children && record.parent) {
480+
if (record && (!record.children || record.children.length === 0) && record.parent) {
481481
leafRowsDirectParents.add(record.parent);
482482
}
483483
});
@@ -494,7 +494,7 @@ export class IgxTreeGridComponent extends IgxGridBaseDirective implements GridTy
494494
if (this.rowSelection === GridSelectionMode.multipleCascade) {
495495
const leafRowsDirectParents = new Set<any>();
496496
this.records.forEach(record => {
497-
if (record && !record.children && record.parent) {
497+
if (record && (!record.children || record.children.length === 0) && record.parent) {
498498
leafRowsDirectParents.add(record.parent);
499499
}
500500
});

projects/igniteui-angular/src/lib/test-utils/sample-test-data.spec.ts

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1142,6 +1142,79 @@ export class SampleTestData {
11421142
}
11431143
]);
11441144

1145+
public static employeeSmallPrimaryForeignKeyTreeData = () => ([
1146+
{
1147+
ID: 147,
1148+
ParentID: -1,
1149+
Name: 'John Winchester',
1150+
HireDate: new Date(2008, 3, 20),
1151+
Age: 55,
1152+
},
1153+
{
1154+
ID: 475,
1155+
ParentID: 147,
1156+
Name: 'Michael Langdon',
1157+
HireDate: new Date(2011, 6, 3),
1158+
Age: 30,
1159+
},
1160+
{
1161+
ID: 957,
1162+
ParentID: 147,
1163+
Name: 'Thomas Hardy',
1164+
HireDate: new Date(2009, 6, 19),
1165+
Age: 29,
1166+
},
1167+
{
1168+
ID: 317,
1169+
ParentID: 147,
1170+
Name: 'Monica Reyes',
1171+
HireDate: new Date(2014, 8, 18),
1172+
Age: 31,
1173+
},
1174+
{
1175+
ID: 711,
1176+
ParentID: 317,
1177+
Name: 'Roland Mendel',
1178+
HireDate: new Date(2015, 9, 17),
1179+
Age: 35
1180+
},
1181+
{
1182+
ID: 998,
1183+
ParentID: 317,
1184+
Name: 'Sven Ottlieb',
1185+
HireDate: new Date(2009, 10, 11),
1186+
Age: 44
1187+
},
1188+
{
1189+
ID: 299,
1190+
ParentID: 317,
1191+
Name: 'Peter Lewis',
1192+
HireDate: new Date(2018, 3, 18),
1193+
Age: 25
1194+
},
1195+
{
1196+
ID: 19,
1197+
ParentID: -1,
1198+
Name: 'Yang Wang',
1199+
HireDate: new Date(2010, 1, 1),
1200+
Age: 61,
1201+
},
1202+
{
1203+
ID: 847,
1204+
ParentID: -1,
1205+
Name: 'Ana Sanders',
1206+
HireDate: new Date(2014, 1, 22),
1207+
Age: 42,
1208+
},
1209+
{
1210+
ID: 663,
1211+
ParentID: 847,
1212+
Name: 'Elizabeth Richards',
1213+
HireDate: new Date(2017, 11, 9),
1214+
Age: 25
1215+
}
1216+
]);
1217+
11451218
/* Search tree data: Every employee node has ID, Name, HireDate, Age, JobTitle and Employees */
11461219
public static employeeSearchTreeData = () => ([
11471220
{
@@ -1399,7 +1472,6 @@ export class SampleTestData {
13991472
Age: 25,
14001473
OnPTO: false
14011474
},
1402-
14031475
{
14041476
ID: 141,
14051477
ParentID: 663,

projects/igniteui-angular/src/lib/test-utils/tree-grid-components.spec.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,3 +973,23 @@ export class IgxTreeGridGroupByAreaTestComponent {
973973
@ViewChild(IgxTreeGridGroupByAreaComponent, { static: true }) public groupByArea: IgxTreeGridGroupByAreaComponent;
974974
}
975975

976+
@Component({
977+
template: `
978+
<igx-tree-grid #treeGrid [data]="data" primaryKey="ID" foreignKey="ParentID" [allowFiltering]="true"
979+
[rowSelection]="'multipleCascade'" [rowEditable]="true" width="900px" height="600px">
980+
<igx-column [field]="'ID'" dataType="number"></igx-column>
981+
<igx-column [field]="'Name'" dataType="string"></igx-column>
982+
<igx-column [field]="'HireDate'" dataType="date"></igx-column>
983+
<igx-column [field]="'Age'" dataType="number"></igx-column>
984+
<igx-action-strip #actionStrip>
985+
<igx-grid-editing-actions [addRow]="true" [addChild]='true'></igx-grid-editing-actions>
986+
</igx-action-strip>
987+
</igx-tree-grid>
988+
`
989+
})
990+
export class IgxTreeGridPrimaryForeignKeyCascadeSelectionComponent {
991+
@ViewChild(IgxTreeGridComponent, { static: true }) public treeGrid: IgxTreeGridComponent;
992+
@ViewChild('actionStrip', { read: IgxActionStripComponent, static: true })
993+
public actionStrip: IgxActionStripComponent;
994+
public data = SampleTestData.employeeSmallPrimaryForeignKeyTreeData();
995+
}

0 commit comments

Comments
 (0)