Skip to content

Update selection changing events #13619

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
325d26b
feat(combos): update selection changing events
wnvko Oct 31, 2023
18d01dc
test(combos): fix failing tests
wnvko Oct 31, 2023
9d80211
Merge branch 'master' into mvenkov/combo-selection-change-event-update
wnvko Oct 31, 2023
e42d1a1
test(simple-combo): fix failing tests
wnvko Oct 31, 2023
8308027
chore(combo): clean up combo common
wnvko Oct 31, 2023
edfd980
feat(combo): emit added and removed as full object
wnvko Nov 2, 2023
be96bdf
feat(combos): add migration for changed properties
wnvko Nov 2, 2023
15b166a
Merge remote-tracking branch 'remotes/origin/master' into mvenkov/com…
wnvko Nov 6, 2023
d24b3eb
Merge branch 'master' into mvenkov/combo-selection-change-event-update
Lipata Nov 6, 2023
7ae525e
Update CHANGELOG.md
wnvko Nov 6, 2023
3c2f976
Update CHANGELOG.md
wnvko Nov 6, 2023
4a3c77a
Update CHANGELOG.md
wnvko Nov 6, 2023
fe8f2a6
test(combo): add test for emitting partial data
wnvko Nov 6, 2023
d13c38c
Merge branch 'master' into mvenkov/combo-selection-change-event-update
Lipata Nov 6, 2023
cf36da5
test(combo): address PR comments
wnvko Nov 6, 2023
b934585
Merge branch 'mvenkov/combo-selection-change-event-update' of https:/…
wnvko Nov 6, 2023
f9d94b5
Merge remote-tracking branch 'remotes/origin/master' into mvenkov/com…
wnvko Nov 7, 2023
7195347
Merge branch 'master' into mvenkov/combo-selection-change-event-update
Lipata Nov 7, 2023
9e745f6
test(simple-combo): fix failing tests
wnvko Nov 7, 2023
0daddfb
test(simple-combo): fix more reactive form related tests
wnvko Nov 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ All notable changes for each version of this project will be documented in this
- We're working on reducing the library size
- IgxRadioComponent has been reduced in half
- IgxSwitchComponent has been reduced in half

- `IgxCombo`
- `IComboSelectionChangingEventArgs` exposes two new properties - `newValue` and `oldValue`. When combo's `valueKey` is set the keys of the items are committed in both. When combo's `valueKey` is not set the entire items are committed. _Note: when combo is working with remote data and a primary key has been set for the selected items that are not currently part of the combo view, will be emitted a partial item data object_
- **Breaking Change** - `IComboSelectionChangingEventArgs` event arguments are changed. Now the `oldSelection`, `newSelection`, `added` and `removed` collections no longer consist of the keys of the selected items when the combo has set a primaryKey, but now in any case the item data is emitted.
When the combo is working with remote data and a primary key has been set for the selected items that are not currently part of the combo view, will be emitted a partial item data object.
- `IgxSimpleCombo`
- **Breaking Change** - `ISimpleComboSelectionChangingEventArgs` event arguments are changed. Now the `oldSelection` and `newSelection` collections no longer consist of the key of the selected item when the combo has set a primaryKey, but now in any case the item data is emitted.
- `ISimpleComboSelectionChangingEventArgs` exposes two new properties - `newValue` and `oldValue`. When combo's `valueKey` is set the key of the item is committed in both. When combo's `valueKey` is not set the entire item is committed.
## 16.1.4
### New Features
- `Themes`:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "../../common/schema/members-changes.schema.json",
"changes": [
{
"member": "newSelection",
"replaceWith": "newValue",
"definedIn": [
"IComboSelectionChangingEventArgs",
"ISimpleComboSelectionChangingEventArgs"
]
},
{
"member": "oldSelection",
"replaceWith": "oldValue",
"definedIn": [
"IComboSelectionChangingEventArgs",
"ISimpleComboSelectionChangingEventArgs"
]
}
]
}
60 changes: 60 additions & 0 deletions projects/igniteui-angular/migrations/update-17_0_0/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,4 +205,64 @@ describe(`Update to ${version}`, () => {
`
);
});

it('Should properly rename newSelection and oldSelection property to newValue and oldValue in Combo', async () => {
pending('set up tests for migrations through lang service');
appTree.create('/testSrc/appPrefix/component/test.component.ts',
`
import { IgxComboComponent, IComboSelectionChangingEventArgs } from 'igniteui-angular';
export class MyClass {
public handleSelectionChanging(e: IComboSelectionChangingEventArgs) {
const newSelection = e.newSelection;
const oldSelection = e.oldSelection;
}
}
`);

const tree = await schematicRunner.runSchematic(migrationName, {}, appTree);

expect(
tree.readContent('/testSrc/appPrefix/component/test.component.ts')
).toEqual(
`
import { IgxComboComponent, IComboSelectionChangingEventArgs } from 'igniteui-angular';
export class MyClass {
public handleSelectionChanging(e: IComboSelectionChangingEventArgs) {
const newSelection = e.newValue;
const oldSelection = e.oldValue;
}
}
`
);
});

it('Should properly rename newSelection and oldSelection property to newValue and oldValue SimpleCombo', async () => {
pending('set up tests for migrations through lang service');
appTree.create('/testSrc/appPrefix/component/test.component.ts',
`
import { IgxSimpleComboComponent, ISimpleComboSelectionChangingEventArgs } from 'igniteui-angular';
export class MyClass {
public handleSelectionChanging(e: ISimpleComboSelectionChangingEventArgs) {
const newSelection = e.newSelection;
const oldSelection = e.oldSelection;
}
}
`);

const tree = await schematicRunner.runSchematic(migrationName, {}, appTree);

expect(
tree.readContent('/testSrc/appPrefix/component/test.component.ts')
).toEqual(
`
import { IgxComboComponent, IComboSelectionChangingEventArgs } from 'igniteui-angular';
export class MyClass {
public handleSelectionChanging(e: IComboSelectionChangingEventArgs) {
const newSelection = e.newValue;
const oldSelection = e.oldValue;
}
}
`
);
});
});
12 changes: 7 additions & 5 deletions projects/igniteui-angular/src/lib/combo/combo.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1294,11 +1294,13 @@ export abstract class IgxComboBaseDirective extends DisplayDensityBase implement
return keys;
}

// map keys vs. filter data to retain the order of the selected items
return keys.map(key => isNaNvalue(key)
? this.data.find(entry => isNaNvalue(entry[this.valueKey]))
: this.data.find(entry => entry[this.valueKey] === key))
.filter(e => e !== undefined);
return keys.map(key => {
const item = isNaNvalue(key)
? this.data.find(entry => isNaNvalue(entry[this.valueKey]))
: this.data.find(entry => entry[this.valueKey] === key);

return item !== undefined ? item : { [this.valueKey]: key };
});
}

protected checkMatch(): void {
Expand Down
94 changes: 67 additions & 27 deletions projects/igniteui-angular/src/lib/combo/combo.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -351,12 +351,17 @@ describe('igxCombo', () => {
spyOnProperty(combo, 'totalItemCount').and.returnValue(combo.data.length);
spyOn(combo.selectionChanging, 'emit');

let oldValue = [];
let newValue = [combo.data[1], combo.data[5], combo.data[6]];

let oldSelection = [];
let newSelection = [combo.data[1], combo.data[5], combo.data[6]];

combo.select(newSelection);
expect(combo.selectionChanging.emit).toHaveBeenCalledTimes(1);
expect(combo.selectionChanging.emit).toHaveBeenCalledWith({
oldValue,
newValue,
oldSelection,
newSelection,
added: newSelection,
Expand All @@ -369,10 +374,14 @@ describe('igxCombo', () => {

let newItem = combo.data[3];
combo.select([newItem]);
oldValue = [...newValue];
newValue.push(newItem);
oldSelection = [...newSelection];
newSelection.push(newItem);
expect(combo.selectionChanging.emit).toHaveBeenCalledTimes(2);
expect(combo.selectionChanging.emit).toHaveBeenCalledWith({
oldValue,
newValue,
oldSelection,
newSelection,
removed: [],
Expand All @@ -383,11 +392,15 @@ describe('igxCombo', () => {
cancel: false
});

oldValue = [...newValue];
newValue = [combo.data[0]];
oldSelection = [...newSelection];
newSelection = [combo.data[0]];
combo.select(newSelection, true);
expect(combo.selectionChanging.emit).toHaveBeenCalledTimes(3);
expect(combo.selectionChanging.emit).toHaveBeenCalledWith({
oldValue,
newValue,
oldSelection,
newSelection,
removed: oldSelection,
Expand All @@ -398,13 +411,17 @@ describe('igxCombo', () => {
cancel: false
});

oldValue = [...newValue];
newValue = [];
oldSelection = [...newSelection];
newSelection = [];
newItem = combo.data[0];
combo.deselect([newItem]);
expect(combo.selection.length).toEqual(0);
expect(combo.selectionChanging.emit).toHaveBeenCalledTimes(4);
expect(combo.selectionChanging.emit).toHaveBeenCalledWith({
oldValue,
newValue,
oldSelection,
newSelection,
removed: [combo.data[0]],
Expand All @@ -428,9 +445,11 @@ describe('igxCombo', () => {
spyOnProperty(combo, 'totalItemCount').and.returnValue(combo.data.length);
const selectionSpy = spyOn(combo.selectionChanging, 'emit');
const expectedResults: IComboSelectionChangingEventArgs = {
newSelection: [combo.data[0][combo.valueKey]],
newValue: [combo.data[0][combo.valueKey]],
oldValue: [],
newSelection: [combo.data[0]],
oldSelection: [],
added: [combo.data[0][combo.valueKey]],
added: [combo.data[0]],
removed: [],
event: undefined,
owner: combo,
Expand All @@ -440,11 +459,13 @@ describe('igxCombo', () => {
combo.select([combo.data[0][combo.valueKey]]);
expect(selectionSpy).toHaveBeenCalledWith(expectedResults);
Object.assign(expectedResults, {
newValue: [],
oldValue: [combo.data[0][combo.valueKey]],
newSelection: [],
oldSelection: [combo.data[0][combo.valueKey]],
oldSelection: [combo.data[0]],
added: [],
displayText: '',
removed: [combo.data[0][combo.valueKey]]
removed: [combo.data[0]]
});
combo.deselect([combo.data[0][combo.valueKey]]);
expect(selectionSpy).toHaveBeenCalledWith(expectedResults);
Expand All @@ -461,42 +482,51 @@ describe('igxCombo', () => {
combo.displayKey = 'city';
combo.dropdown = dropdown;
spyOnProperty(combo, 'totalItemCount').and.returnValue(combo.data.length);
const selectionSpy = spyOn(combo.selectionChanging, 'emit');

let oldSelection = [];
let newSelection = [combo.data[0], combo.data[1], combo.data[2]];
const selectionSpy = spyOn(combo.selectionChanging, 'emit');
combo.select(newSelection.map(e => e[combo.valueKey]));
const expectedResults: IComboSelectionChangingEventArgs = {
newSelection: newSelection.map(e => e[combo.valueKey]),
newValue: newSelection.map(e => e[combo.valueKey]),
oldValue: [],
newSelection: newSelection,
oldSelection,
added: newSelection.map(e => e[combo.valueKey]),
added: newSelection,
removed: [],
event: undefined,
owner: combo,
displayText: `${newSelection.map(entry => entry[combo.displayKey]).join(', ')}`,
cancel: false
};
combo.select(newSelection.map(e => e[combo.valueKey]));
expect(selectionSpy).toHaveBeenCalledWith(expectedResults);
oldSelection = [...newSelection].map(e => e[combo.valueKey]);

oldSelection = [...newSelection];
newSelection = [combo.data[1], combo.data[2]];
combo.deselect([combo.data[0][combo.valueKey]]);
Object.assign(expectedResults, {
newSelection: newSelection.map(e => e[combo.valueKey]),
newValue: newSelection.map(e => e[combo.valueKey]),
oldValue: oldSelection.map(e => e[combo.valueKey]),
newSelection,
oldSelection,
added: [],
displayText: newSelection.map(e => e[combo.displayKey]).join(', '),
removed: [combo.data[0][combo.valueKey]]
removed: [combo.data[0]]
});
oldSelection = [...newSelection].map(e => e[combo.valueKey]);
newSelection = [combo.data[4], combo.data[5], combo.data[6]];
expect(selectionSpy).toHaveBeenCalledWith(expectedResults);

oldSelection = [...newSelection];
newSelection = [combo.data[4], combo.data[5], combo.data[6]];
combo.select(newSelection.map(e => e[combo.valueKey]), true);
Object.assign(expectedResults, {
newSelection: newSelection.map(e => e[combo.valueKey]),
newValue: newSelection.map(e => e[combo.valueKey]),
oldValue: oldSelection.map(e => e[combo.valueKey]),
newSelection,
oldSelection,
added: newSelection.map(e => e[combo.valueKey]),
added: newSelection,
displayText: newSelection.map(e => e[combo.displayKey]).join(', '),
removed: oldSelection
});
combo.select(newSelection.map(e => e[combo.valueKey]), true);
expect(selectionSpy).toHaveBeenCalledWith(expectedResults);
});
it('should handle select/deselect ALL items', () => {
Expand Down Expand Up @@ -537,6 +567,8 @@ describe('igxCombo', () => {
expect(combo.value).toEqual(data);
expect(combo.selectionChanging.emit).toHaveBeenCalledTimes(1);
expect(combo.selectionChanging.emit).toHaveBeenCalledWith({
oldValue: [],
newValue: data,
oldSelection: [],
newSelection: data,
added: data,
Expand All @@ -552,6 +584,8 @@ describe('igxCombo', () => {
expect(combo.value).toEqual([]);
expect(combo.selectionChanging.emit).toHaveBeenCalledTimes(2);
expect(combo.selectionChanging.emit).toHaveBeenCalledWith({
oldValue: data,
newValue: [],
oldSelection: data,
newSelection: [],
added: [],
Expand All @@ -572,7 +606,7 @@ describe('igxCombo', () => {
combo.data = data;
combo.dropdown = dropdown;
spyOnProperty(combo, 'totalItemCount').and.returnValue(combo.data.length);
spyOn(combo.selectionChanging, 'emit').and.callFake((event: IComboSelectionChangingEventArgs) => event.newSelection = []);
spyOn(combo.selectionChanging, 'emit').and.callFake((event: IComboSelectionChangingEventArgs) => event.newValue = []);
// No items are initially selected
expect(combo.selection).toEqual([]);
// Select the first 5 items
Expand Down Expand Up @@ -1335,9 +1369,9 @@ describe('igxCombo', () => {
expect(combo.value).toEqual([]);

// current combo data - id: 0 - 9
// select item that is not present in the data source yet
// select item that is not present in the data source yet should be added as partial item
combo.select([9, 19]);
expect(combo.selection.length).toEqual(1);
expect(combo.selection.length).toEqual(2);
expect(combo.value.length).toEqual(2);

const firstItem = combo.data[combo.data.length - 1];
Expand Down Expand Up @@ -1975,9 +2009,11 @@ describe('igxCombo', () => {
expect(combo.selectionChanging.emit).toHaveBeenCalledTimes(1);
expect(combo.selectionChanging.emit).toHaveBeenCalledWith(
{
newSelection: [selectedItem_1.value[combo.valueKey]],
newValue: [selectedItem_1.value[combo.valueKey]],
oldValue: [],
newSelection: [selectedItem_1.value],
oldSelection: [],
added: [selectedItem_1.value[combo.valueKey]],
added: [selectedItem_1.value],
removed: [],
event: UIInteractions.getMouseEvent('click'),
owner: combo,
Expand All @@ -1994,9 +2030,11 @@ describe('igxCombo', () => {
expect(combo.selectionChanging.emit).toHaveBeenCalledTimes(2);
expect(combo.selectionChanging.emit).toHaveBeenCalledWith(
{
newSelection: [selectedItem_1.value[combo.valueKey], selectedItem_2.value[combo.valueKey]],
oldSelection: [selectedItem_1.value[combo.valueKey]],
added: [selectedItem_2.value[combo.valueKey]],
newValue: [selectedItem_1.value[combo.valueKey], selectedItem_2.value[combo.valueKey]],
oldValue: [selectedItem_1.value[combo.valueKey]],
newSelection: [selectedItem_1.value, selectedItem_2.value],
oldSelection: [selectedItem_1.value],
added: [selectedItem_2.value],
removed: [],
event: UIInteractions.getMouseEvent('click'),
owner: combo,
Expand All @@ -2013,10 +2051,12 @@ describe('igxCombo', () => {
expect(combo.selectionChanging.emit).toHaveBeenCalledTimes(3);
expect(combo.selectionChanging.emit).toHaveBeenCalledWith(
{
newSelection: [selectedItem_2.value[combo.valueKey]],
oldSelection: [selectedItem_1.value[combo.valueKey], selectedItem_2.value[combo.valueKey]],
newValue: [selectedItem_2.value[combo.valueKey]],
oldValue: [selectedItem_1.value[combo.valueKey], selectedItem_2.value[combo.valueKey]],
newSelection: [selectedItem_2.value],
oldSelection: [selectedItem_1.value, selectedItem_2.value],
added: [],
removed: [unselectedItem.value[combo.valueKey]],
removed: [unselectedItem.value],
event: UIInteractions.getMouseEvent('click'),
owner: combo,
displayText: selectedItem_2.value[combo.valueKey],
Expand Down
Loading