Skip to content

Commit 341b280

Browse files
authored
Merge pull request #8191 from IgniteUI/mdragnev/add-row-transactions
Assign 'fake' id to the newly added row so that transactions could work
2 parents 50af1cb + f4cc4cb commit 341b280

File tree

11 files changed

+283
-29
lines changed

11 files changed

+283
-29
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,21 @@ All notable changes for each version of this project will be documented in this
2323
- `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid`
2424
- When triggering an export of the grid via the toolbar and the export takes more than 500 milliseconds, the export button becomes disabled and an indeterminate progress bar is shown at the bottom of the toolbar until the export is finished.
2525
- Added *getRowData(rowSelector)* method that returns an object that represents the data that is contained in the specified row component.
26+
- Added ability to spawn row adding UI through exoposed methods. Note that rowEditing should be enabled.
27+
- `beginAddRow` method which starts the adding row UI.
28+
- `beginAddChild` method which starts the adding child UI.
29+
```typescript
30+
this.grid.beginAddRow(rowID);
31+
```
32+
- Added an input properties to `IgxGridEditingActions` component to show/hide add row and add child buttons which trigger the UI based on context expression.
33+
```html
34+
<igx-tree-grid [rowEditing]="true">
35+
<igx-action-strip #actionStrip>
36+
<igx-grid-editing-actions [addRow]="true" [addChild]="actionStrip.context.level < 3">
37+
</igx-grid-editing-actions>
38+
</igx-action-strip>
39+
</igx-tree-grid>
40+
```
2641
- ` IGX_INPUT_GROUP_TYPE` injection token
2742
- Allows for setting an input group `type` on a global level, so all input-group instances, including components using such an instance as a template will have their input group type set to the one specified by the token. It can be overridden on a component level by explicitly setting a `type`.
2843
- ` IgxExcelExporterService`

projects/igniteui-angular/src/lib/grids/api.service.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,21 @@ export class GridBaseAPIService <T extends IgxGridBaseDirective & GridType> {
148148
public update_add_cell(cell: IgxCell, value: any) {
149149
cell.editValue = value;
150150

151-
if (isEqual(cell.value, cell.editValue)) {
152-
return;
151+
const args = cell.createEditEventArgs();
152+
this.grid.onCellEdit.emit(args);
153+
154+
if (args.cancel) {
155+
return args;
156+
}
157+
158+
if (isEqual(args.oldValue, args.newValue)) {
159+
return args;
153160
}
154161
const data = cell.rowData;
155-
this.updateData(this.grid, cell.id.rowID, data, cell.rowData, reverseMapper(cell.column.field, cell.editValue));
162+
mergeObjects(data, reverseMapper(cell.column.field, args.newValue));
163+
const doneArgs = cell.createDoneEditEventArgs(args.newValue);
164+
doneArgs.rowData = data;
165+
this.grid.cellEditDone.emit(doneArgs);
156166
}
157167

158168
update_cell(cell: IgxCell, value: any) {

projects/igniteui-angular/src/lib/grids/cell.component.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,13 +178,13 @@ export class IgxGridCellComponent implements OnInit, OnChanges, OnDestroy {
178178
* @memberof IgxGridCellComponent
179179
*/
180180
get template(): TemplateRef<any> {
181-
if (this.grid.rowEditable && this.row.addRow) {
182-
return this.addMode ? this.inlineEditorTemplate : this.addRowCellTemplate;
183-
}
184-
if (this.editMode) {
181+
if (this.editMode || this.addMode) {
185182
const inlineEditorTemplate = this.column.inlineEditorTemplate;
186183
return inlineEditorTemplate ? inlineEditorTemplate : this.inlineEditorTemplate;
187184
}
185+
if (this.grid.rowEditable && this.row.addRow) {
186+
return this.addRowCellTemplate;
187+
}
188188
if (this.cellTemplate) {
189189
return this.cellTemplate;
190190
}

projects/igniteui-angular/src/lib/grids/common/events.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export interface IGridEditDoneEventArgs extends IBaseEventArgs {
3333
event?: Event;
3434
column?: ColumnType;
3535
owner?: IgxGridBaseDirective & GridType;
36+
isAddRow?: boolean;
3637
}
3738

3839
export interface IGridEditEventArgs extends CancelableEventArgs, IGridEditDoneEventArgs {

projects/igniteui-angular/src/lib/grids/common/pipes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ export class IgxGridAddRowPipe implements PipeTransform {
374374

375375
const row = {...collection[parentIndex]};
376376
Object.keys(row).forEach(key => row[key] = undefined);
377+
row[grid.primaryKey] = grid.generateRowID();
377378
const rec = {
378379
recordRef: row,
379380
addRow: true

projects/igniteui-angular/src/lib/grids/grid-base.directive.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ import { IGridSortingStrategy } from '../data-operations/sorting-strategy';
150150
import { IgxRowDragGhostDirective, IgxDragIndicatorIconDirective } from './row-drag.directive';
151151
import { IgxGridExcelStyleFilteringComponent } from './filtering/excel-style/grid.excel-style-filtering.component';
152152
import { IgxSnackbarComponent } from '../snackbar/snackbar.component';
153+
import { v4 as uuidv4 } from 'uuid';
154+
155+
let FAKE_ROW_ID = -1;
153156

154157
const MINIMUM_COLUMN_WIDTH = 136;
155158
const FILTER_ROW_HEIGHT = 50;
@@ -3103,6 +3106,15 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements
31033106
this.columnList.forEach(column => column.resetCaches());
31043107
}
31053108

3109+
/**
3110+
* @hidden @internal
3111+
*/
3112+
public generateRowID(): string | number {
3113+
const primaryColumn = this.columnList.find(col => col.field === this.primaryKey);
3114+
const idType = primaryColumn ? primaryColumn.dataType : this.data.length ? typeof (this.data[0][this.primaryKey]) : 'string';
3115+
return idType === 'string' ? uuidv4() : FAKE_ROW_ID--;
3116+
}
3117+
31063118
/**
31073119
* @hidden
31083120
* @internal
@@ -6549,7 +6561,7 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements
65496561
if (commit) {
65506562
this.onRowAdded.subscribe(rowData => {
65516563
// A check whether the row is in the current view
6552-
const index = this.dataView.findIndex(data => data === rowData);
6564+
const index = this.dataView.findIndex(data => data[this.primaryKey] === rowData[this.primaryKey]);
65536565
const shouldScroll = this.navigation.shouldPerformVerticalScroll(index, 0);
65546566
const showIndex = shouldScroll ? index : -1;
65556567
this.showSnackbarFor(showIndex);
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { IgxGridModule, IgxGridComponent } from './public_api';
2+
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
3+
import { async, TestBed, fakeAsync } from '@angular/core/testing';
4+
import { configureTestSuite } from '../../test-utils/configure-suite';
5+
import { DebugElement } from '@angular/core';
6+
import { GridFunctions } from '../../test-utils/grid-functions.spec';
7+
import {
8+
IgxAddRowComponent
9+
} from '../../test-utils/grid-samples.spec';
10+
11+
import { By } from '@angular/platform-browser';
12+
import { IgxActionStripComponent } from '../../action-strip/action-strip.component';
13+
import { IgxActionStripModule } from '../../action-strip/action-strip.module';
14+
import { UIInteractions } from '../../test-utils/ui-interactions.spec';
15+
16+
describe('IgxGrid - Row Adding #grid', () => {
17+
let fixture;
18+
let grid: IgxGridComponent;
19+
let gridContent: DebugElement;
20+
let actionStrip: IgxActionStripComponent;
21+
configureTestSuite();
22+
beforeAll(async(() => {
23+
TestBed.configureTestingModule({
24+
declarations: [
25+
IgxAddRowComponent
26+
],
27+
imports: [
28+
NoopAnimationsModule,
29+
IgxActionStripModule,
30+
IgxGridModule]
31+
}).compileComponents();
32+
}));
33+
34+
describe('General tests', () => {
35+
beforeEach(fakeAsync(/** height/width setter rAF */() => {
36+
fixture = TestBed.createComponent(IgxAddRowComponent);
37+
fixture.detectChanges();
38+
grid = fixture.componentInstance.grid;
39+
gridContent = GridFunctions.getGridContent(fixture);
40+
actionStrip = fixture.componentInstance.actionStrip;
41+
}));
42+
43+
it('Should be able to enter add row mode on action strip click', () => {
44+
const row = grid.rowList.first;
45+
actionStrip.show(row);
46+
fixture.detectChanges();
47+
const addRowIcon = fixture.debugElement.queryAll(By.css(`igx-grid-editing-actions igx-icon`))[1];
48+
addRowIcon.parent.triggerEventHandler('click', new Event('click'));
49+
fixture.detectChanges();
50+
const addRow = grid.getRowByIndex(1);
51+
expect(addRow.addRow).toBeTrue();
52+
});
53+
54+
it('Should be able to enter add row mode through the exposed API method (w/ and w/o rowID)', () => {
55+
grid.beginAddRow();
56+
fixture.detectChanges();
57+
let addRow = grid.getRowByIndex(1);
58+
expect(addRow.addRow).toBeTrue();
59+
60+
UIInteractions.triggerEventHandlerKeyDown('escape', gridContent);
61+
fixture.detectChanges();
62+
addRow = grid.getRowByIndex(1);
63+
expect(addRow.addRow).toBeFalse();
64+
65+
grid.beginAddRow('ANATR');
66+
fixture.detectChanges();
67+
addRow = grid.getRowByIndex(2);
68+
expect(addRow.addRow).toBeTrue();
69+
});
70+
71+
it('Should display the banner above the row if there is no room underneath it', () => {
72+
grid.paging = true;
73+
grid.perPage = 7;
74+
fixture.detectChanges();
75+
76+
const lastRow = grid.rowList.last;
77+
const lastRowIndex = lastRow.index;
78+
actionStrip.show(lastRow);
79+
fixture.detectChanges();
80+
81+
const addRowIcon = fixture.debugElement.queryAll(By.css(`igx-grid-editing-actions igx-icon`))[1];
82+
addRowIcon.parent.triggerEventHandler('click', new Event('click'));
83+
fixture.detectChanges();
84+
85+
86+
const addRow = grid.getRowByIndex(lastRowIndex + 1);
87+
expect(addRow.addRow).toBeTrue();
88+
89+
const banner = GridFunctions.getRowEditingOverlay(fixture);
90+
fixture.detectChanges();
91+
const bannerBottom = banner.getBoundingClientRect().bottom;
92+
const addRowTop = addRow.nativeElement.getBoundingClientRect().top;
93+
94+
// The banner appears above the row
95+
expect(bannerBottom).toBeLessThanOrEqual(addRowTop);
96+
97+
// No much space between the row and the banner
98+
expect(addRowTop - bannerBottom).toBeLessThan(2);
99+
});
100+
101+
it('Should not be able to enter add row mode when rowEditing is disabled', () => {
102+
grid.rowEditable = false;
103+
fixture.detectChanges();
104+
105+
grid.beginAddRow();
106+
fixture.detectChanges();
107+
108+
const banner = GridFunctions.getRowEditingOverlay(fixture);
109+
expect(banner).toBeNull();
110+
expect(grid.getRowByIndex(1).addRow).toBeFalse();
111+
});
112+
113+
});
114+
});

projects/igniteui-angular/src/lib/grids/grid/grid-row-editing.spec.ts

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ describe('IgxGrid - Row Editing #grid', () => {
156156
rowData: initialRowData,
157157
oldValue: row.rowData,
158158
cancel: false,
159-
owner: grid
159+
owner: grid,
160+
isAddRow: row.addRow
160161
};
161162
expect(grid.onCellEditEnter.emit).toHaveBeenCalledWith(cellArgs);
162163
expect(grid.onRowEditEnter.emit).toHaveBeenCalledWith(rowArgs);
@@ -183,7 +184,8 @@ describe('IgxGrid - Row Editing #grid', () => {
183184
newValue: null,
184185
oldValue: row.rowData,
185186
cancel: false,
186-
owner: grid
187+
owner: grid,
188+
isAddRow: row.addRow
187189
};
188190
expect(grid.onCellEditCancel.emit).toHaveBeenCalledWith(cellArgs);
189191
expect(grid.onRowEditCancel.emit).toHaveBeenCalledWith(rowArgs);
@@ -213,7 +215,8 @@ describe('IgxGrid - Row Editing #grid', () => {
213215
newValue: Object.assign({}, row.rowData, { ProductName: newCellValue }),
214216
oldValue: row.rowData,
215217
cancel: false,
216-
owner: grid
218+
owner: grid,
219+
isAddRow: row.addRow
217220
};
218221

219222
const cellDoneArgs: IGridEditDoneEventArgs = {
@@ -231,7 +234,8 @@ describe('IgxGrid - Row Editing #grid', () => {
231234
rowData: updatedRowData, // with rowEditable - IgxGridRowEditingComponent
232235
oldValue: row.rowData,
233236
newValue: Object.assign({}, row.rowData, { ProductName: newCellValue }),
234-
owner: grid
237+
owner: grid,
238+
isAddRow: row.addRow
235239
};
236240
UIInteractions.triggerEventHandlerKeyDown('enter', gridContent);
237241

@@ -1604,7 +1608,8 @@ describe('IgxGrid - Row Editing #grid', () => {
16041608
newValue: Object.assign({}, initialData, { ProductName: 'New Name' }),
16051609
oldValue: initialData,
16061610
cancel: false,
1607-
owner: grid
1611+
owner: grid,
1612+
isAddRow: false
16081613
});
16091614
});
16101615

@@ -1641,7 +1646,8 @@ describe('IgxGrid - Row Editing #grid', () => {
16411646
newValue: Object.assign({}, initialData, { ProductName: 'New Name' }),
16421647
oldValue: initialData,
16431648
cancel: true,
1644-
owner: grid
1649+
owner: grid,
1650+
isAddRow: false
16451651
});
16461652

16471653
// Enter cell edit mode again
@@ -1663,7 +1669,8 @@ describe('IgxGrid - Row Editing #grid', () => {
16631669
newValue: Object.assign({}, initialData, { ProductName: 'New Name' }),
16641670
oldValue: initialData,
16651671
cancel: true,
1666-
owner: grid
1672+
owner: grid,
1673+
isAddRow: false
16671674
});
16681675
});
16691676

@@ -1692,7 +1699,8 @@ describe('IgxGrid - Row Editing #grid', () => {
16921699
newValue: null,
16931700
oldValue: initialData,
16941701
cancel: false,
1695-
owner: grid
1702+
owner: grid,
1703+
isAddRow: false
16961704
});
16971705
});
16981706

@@ -1730,7 +1738,8 @@ describe('IgxGrid - Row Editing #grid', () => {
17301738
newValue: null,
17311739
oldValue: initialData,
17321740
cancel: true,
1733-
owner: grid
1741+
owner: grid,
1742+
isAddRow: false
17341743
});
17351744

17361745
// Enter cell edit mode again
@@ -1753,7 +1762,8 @@ describe('IgxGrid - Row Editing #grid', () => {
17531762
newValue: null,
17541763
oldValue: initialData,
17551764
cancel: true,
1756-
owner: grid
1765+
owner: grid,
1766+
isAddRow: false
17571767
});
17581768
});
17591769

@@ -1777,7 +1787,8 @@ describe('IgxGrid - Row Editing #grid', () => {
17771787
rowData: initialData,
17781788
oldValue: initialData,
17791789
cancel: false,
1780-
owner: grid
1790+
owner: grid,
1791+
isAddRow: false
17811792
});
17821793
});
17831794

@@ -1804,7 +1815,8 @@ describe('IgxGrid - Row Editing #grid', () => {
18041815
rowData: initialData,
18051816
oldValue: initialData,
18061817
cancel: true,
1807-
owner: grid
1818+
owner: grid,
1819+
isAddRow: false
18081820
});
18091821
});
18101822

@@ -1834,7 +1846,8 @@ describe('IgxGrid - Row Editing #grid', () => {
18341846
newValue: Object.assign({}, initialData, { ProductName: 'New Name' }),
18351847
oldValue: initialData,
18361848
cancel: false,
1837-
owner: grid
1849+
owner: grid,
1850+
isAddRow: false
18381851
});
18391852
});
18401853

@@ -1863,7 +1876,8 @@ describe('IgxGrid - Row Editing #grid', () => {
18631876
newValue: null,
18641877
oldValue: initialData,
18651878
cancel: false,
1866-
owner: grid
1879+
owner: grid,
1880+
isAddRow: false
18671881
});
18681882
});
18691883

@@ -2087,7 +2101,8 @@ describe('IgxGrid - Row Editing #grid', () => {
20872101
rowData: updatedRowData, // with rowEditable&Transactions - IgxGridRowEditingTransactionComponent
20882102
oldValue: row.rowData,
20892103
newValue: Object.assign({}, row.rowData, { ProductName: newCellValue }),
2090-
owner: grid
2104+
owner: grid,
2105+
isAddRow: row.addRow
20912106
};
20922107

20932108
UIInteractions.triggerEventHandlerKeyDown('enter', gridContent);

0 commit comments

Comments
 (0)