Skip to content

Commit e5cbaf8

Browse files
authored
Merge branch 'master' into mkirkova/feat-12522
2 parents 72efb07 + da97e28 commit e5cbaf8

File tree

4 files changed

+169
-41
lines changed

4 files changed

+169
-41
lines changed

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,40 @@ describe('IgxGrid - Row Editing #grid', () => {
851851
expect(GridFunctions.getRowEditingBannerText(fix)).toBe('You have 2 changes in this row and 1 hidden columns');
852852
}));
853853

854+
it(`Should show no row changes when changing the cell value to the original one`, () => {
855+
targetCell = grid.gridAPI.get_cell_by_index(0, 'Downloads');
856+
fix.detectChanges();
857+
858+
const originalValue = targetCell.value;
859+
860+
UIInteractions.simulateDoubleClickAndSelectEvent(targetCell);
861+
fix.detectChanges();
862+
863+
// change first editable cell value
864+
targetCell.editValue = '500';
865+
fix.detectChanges();
866+
867+
// go to next cell
868+
UIInteractions.triggerEventHandlerKeyDown('tab', gridContent);
869+
fix.detectChanges();
870+
871+
expect(GridFunctions.getRowEditingBannerText(fix)).toBe('You have 1 changes in this row and 0 hidden columns');
872+
873+
// return to first editable cell
874+
UIInteractions.triggerEventHandlerKeyDown('tab', gridContent, false, true);
875+
fix.detectChanges();
876+
877+
// change cell value to the original one
878+
targetCell.editValue = originalValue;
879+
fix.detectChanges();
880+
881+
// go to next cell
882+
UIInteractions.triggerEventHandlerKeyDown('tab', gridContent);
883+
fix.detectChanges();
884+
885+
expect(GridFunctions.getRowEditingBannerText(fix)).toBe('You have 0 changes in this row and 0 hidden columns');
886+
});
887+
854888
it(`Should focus last edited cell after click on editable buttons`, (async () => {
855889
targetCell = grid.gridAPI.get_cell_by_index(0, 'Downloads');
856890
UIInteractions.simulateDoubleClickAndSelectEvent(targetCell);

projects/igniteui-angular/src/lib/services/transaction/base-transaction.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { TransactionService, Transaction, State, StateUpdateEvent } from './transaction';
1+
import { TransactionService, Transaction, State, StateUpdateEvent, TransactionType } from './transaction';
22
import { EventEmitter } from '@angular/core';
33
import { isObject, mergeObjects } from '../../core/utils';
44
import { DefaultDataCloneStrategy, IDataCloneStrategy } from '../../data-operations/data-clone-strategy';
@@ -157,6 +157,8 @@ export class IgxBaseTransactionService<T extends Transaction, S extends State> i
157157
state = { value: this.cloneStrategy.clone(transaction.newValue), recordRef, type: transaction.type } as S;
158158
states.set(transaction.id, state);
159159
}
160+
161+
this.cleanState(transaction.id, states);
160162
}
161163

162164
/**
@@ -183,4 +185,40 @@ export class IgxBaseTransactionService<T extends Transaction, S extends State> i
183185
return second ? second : first;
184186
}
185187
}
188+
189+
/**
190+
* Compares the state with recordRef and clears all duplicated values. If any state ends as
191+
* empty object removes it from states.
192+
*
193+
* @param state State to clean
194+
*/
195+
protected cleanState(id: any, states: Map<any, S>): void {
196+
const state = states.get(id);
197+
// do nothing if
198+
// there is no state, or
199+
// there is no state value (e.g. DELETED transaction), or
200+
// there is no recordRef (e.g. ADDED transaction)
201+
if (state && state.value && state.recordRef) {
202+
// if state's value is object compare each key with the ones in recordRef
203+
// if values in any key are the same delete it from state's value
204+
// if state's value is not object, simply compare with recordRef and remove
205+
// the state if they are equal
206+
if (isObject(state.recordRef)) {
207+
for (const key of Object.keys(state.value)) {
208+
if (JSON.stringify(state.recordRef[key]) === JSON.stringify(state.value[key])) {
209+
delete state.value[key];
210+
}
211+
}
212+
213+
// if state's value is empty remove the state from the states, only if state is not DELETE type
214+
if (state.type !== TransactionType.DELETE && Object.keys(state.value).length === 0) {
215+
states.delete(id);
216+
}
217+
} else {
218+
if (state.recordRef === state.value) {
219+
states.delete(id);
220+
}
221+
}
222+
}
223+
}
186224
}

projects/igniteui-angular/src/lib/services/transaction/igx-transaction.spec.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,32 @@ describe('IgxTransaction', () => {
740740
expect(trans.onStateUpdate.emit).toHaveBeenCalledTimes(0);
741741
});
742742

743+
it('Should not generate changes when updating a value to the original one', () => {
744+
const originalData = SampleTestData.generateProductData(50);
745+
const transaction = new IgxTransactionService();
746+
expect(transaction).toBeDefined();
747+
748+
transaction.startPending();
749+
750+
const itemUpdate1: Transaction = { id: 1, type: TransactionType.UPDATE, newValue: { Category: 'Some new value' } };
751+
transaction.add(itemUpdate1, originalData[1]);
752+
753+
expect(transaction.getState(1, true)).toBeTruthy();
754+
expect(transaction.getAggregatedValue(1, false)).toEqual({ Category: 'Some new value' });
755+
756+
// update to original value
757+
const itemUpdate2: Transaction = { id: 1, type: TransactionType.UPDATE, newValue: { Category: originalData[1].Category } };
758+
transaction.add(itemUpdate2, originalData[1]);
759+
760+
expect(transaction.getState(1, true)).toBeUndefined();
761+
expect(transaction.getAggregatedValue(1, false)).toBeNull();
762+
763+
transaction.endPending(false);
764+
765+
expect(transaction.getTransactionLog()).toEqual([]);
766+
expect(transaction.getAggregatedChanges(true)).toEqual([]);
767+
});
768+
743769
it('Should clear transactions for provided id', () => {
744770
const originalData = SampleTestData.generateProductData(50);
745771
const trans = new IgxTransactionService();
@@ -936,6 +962,75 @@ describe('IgxTransaction', () => {
936962
expect(transaction.getAggregatedChanges(false).length).toBe(0);
937963
});
938964

965+
it('Should not generate changes when updating a value to the original one', () => {
966+
const originalData = SampleTestData.employeeTreeData();
967+
const transaction = new IgxHierarchicalTransactionService();
968+
expect(transaction).toBeDefined();
969+
970+
transaction.startPending();
971+
972+
// root record update
973+
const rootUpdate1: HierarchicalTransaction = {
974+
id: 147,
975+
type: TransactionType.UPDATE,
976+
newValue: {
977+
Name: 'New Name'
978+
},
979+
path: null
980+
};
981+
transaction.add(rootUpdate1, originalData[0]);
982+
983+
expect(transaction.getState(147, true)).toBeTruthy();
984+
expect(transaction.getAggregatedValue(147, false)).toEqual({ Name: 'New Name' });
985+
986+
// update to original value
987+
const rootUpdate2: HierarchicalTransaction = {
988+
id: 147,
989+
type: TransactionType.UPDATE,
990+
newValue: {
991+
Name: originalData[0].Name
992+
},
993+
path: null
994+
};
995+
transaction.add(rootUpdate2, originalData[0]);
996+
997+
expect(transaction.getState(147, true)).toBeUndefined();
998+
expect(transaction.getAggregatedValue(147, false)).toBeNull();
999+
1000+
// child record update
1001+
const childUpdate1: HierarchicalTransaction = {
1002+
id: 475,
1003+
type: TransactionType.UPDATE,
1004+
newValue: {
1005+
Age: 60
1006+
},
1007+
path: [originalData[0].ID]
1008+
};
1009+
transaction.add(childUpdate1, originalData[0].Employees[0]);
1010+
1011+
expect(transaction.getState(475, true)).toBeTruthy();
1012+
expect(transaction.getAggregatedValue(475, false)).toEqual({ Age: 60 });
1013+
1014+
// update to original value
1015+
const childUpdate2: HierarchicalTransaction = {
1016+
id: 475,
1017+
type: TransactionType.UPDATE,
1018+
newValue: {
1019+
Age: originalData[0].Employees[0].Age
1020+
},
1021+
path: [originalData[0].ID]
1022+
};
1023+
transaction.add(childUpdate2, originalData[0].Employees[0]);
1024+
1025+
expect(transaction.getState(475, true)).toBeUndefined();
1026+
expect(transaction.getAggregatedValue(475, false)).toBeNull();
1027+
1028+
transaction.endPending(false);
1029+
1030+
expect(transaction.getTransactionLog()).toEqual([]);
1031+
expect(transaction.getAggregatedChanges(true)).toEqual([]);
1032+
});
1033+
9391034
it('Should emit onStateUpdate once when commiting a hierarchical transaction', () => {
9401035
const data = SampleTestData.employeeTreeData();
9411036
const transaction = new IgxHierarchicalTransactionService();

projects/igniteui-angular/src/lib/services/transaction/igx-transaction.ts

Lines changed: 1 addition & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -283,46 +283,7 @@ export class IgxTransactionService<T extends Transaction, S extends State> exten
283283
states.set(transaction.id, state);
284284
}
285285

286-
// should not clean pending state. This will happen automatically on endPending call
287-
if (!this._isPending) {
288-
this.cleanState(transaction.id, states);
289-
}
290-
}
291-
292-
/**
293-
* Compares the state with recordRef and clears all duplicated values. If any state ends as
294-
* empty object removes it from states.
295-
*
296-
* @param state State to clean
297-
*/
298-
protected cleanState(id: any, states: Map<any, S>): void {
299-
const state = states.get(id);
300-
// do nothing if
301-
// there is no state, or
302-
// there is no state value (e.g. DELETED transaction), or
303-
// there is no recordRef (e.g. ADDED transaction)
304-
if (state && state.value && state.recordRef) {
305-
// if state's value is object compare each key with the ones in recordRef
306-
// if values in any key are the same delete it from state's value
307-
// if state's value is not object, simply compare with recordRef and remove
308-
// the state if they are equal
309-
if (isObject(state.recordRef)) {
310-
for (const key of Object.keys(state.value)) {
311-
if (JSON.stringify(state.recordRef[key]) === JSON.stringify(state.value[key])) {
312-
delete state.value[key];
313-
}
314-
}
315-
316-
// if state's value is empty remove the state from the states, only if state is not DELETE type
317-
if (state.type !== TransactionType.DELETE && Object.keys(state.value).length === 0) {
318-
states.delete(id);
319-
}
320-
} else {
321-
if (state.recordRef === state.value) {
322-
states.delete(id);
323-
}
324-
}
325-
}
286+
this.cleanState(transaction.id, states);
326287
}
327288

328289
/**

0 commit comments

Comments
 (0)