Skip to content

Commit 32329e9

Browse files
committed
feat(combo): add display text overwrite to selection change event, #6342
1 parent 299f101 commit 32329e9

File tree

3 files changed

+98
-41
lines changed

3 files changed

+98
-41
lines changed

CHANGELOG.md

+17
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,23 @@ All notable changes for each version of this project will be documented in this
8383
- `IgxSelect`:
8484
- adding `IgxSelectHeaderDirective` and `IgxSelectFooterDirective`. These can be used to provide a custom header, respectively footer templates for the `igxSelect` drop-down list. If there are no templates marked with these directives - no default templates will be used so the drop-down list will not have header nor footer.
8585

86+
- `IgxCombo`:
87+
- Added `textValue` property to the combo's `onSelectionChange` event args. The property contains the text that will be populated in the combo's text box **after** selection completes. This text can be overwritten in order to display a custom message, e.g. "3 items selected":
88+
```html
89+
<igx-combo [data]="people" valueKey="id" displayKey="name" placeholder="Invite friends..." (onSelectionChange)="handleSelection($event)">
90+
```
91+
```typescript
92+
export class MyInvitationComponent {
93+
public people: { name: string; id: string }[] = [...];
94+
...
95+
handleSelection(event: IComboSelectionChangeEventArgs) {
96+
const count = event.newSelection.length;
97+
event.textValue = count > 0 ? `${count} friend${count > 1 ? 's' : ''} invited!` : `No friends invited :(`;
98+
}
99+
...
100+
}
101+
```
102+
86103
- `IgxDropDown`:
87104
- `clearSelection` method is added, which can be used to deselect the selected dropdown item
88105

projects/igniteui-angular/src/lib/combo/combo.component.spec.ts

+62-40
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,7 @@ describe('igxCombo', () => {
10201020
newSelection: [targetItem.itemID],
10211021
added: [targetItem.itemID],
10221022
removed: [],
1023+
textValue: `${targetItem.value[combo.displayKey]}`,
10231024
event: undefined,
10241025
cancel: false
10251026
});
@@ -1034,6 +1035,7 @@ describe('igxCombo', () => {
10341035
newSelection: [],
10351036
added: [],
10361037
removed: [targetItem.itemID],
1038+
textValue: '',
10371039
event: undefined,
10381040
cancel: false
10391041
});
@@ -1045,57 +1047,61 @@ describe('igxCombo', () => {
10451047
spyOn(combo.onSelectionChange, 'emit');
10461048
let oldSelection = [];
10471049
let newSelection = [combo.data[1], combo.data[5], combo.data[6]];
1050+
let newSelectionKeys = newSelection.map(entry => entry[combo.valueKey]);
10481051

10491052
combo.toggle();
10501053
tick();
10511054
fix.detectChanges();
1052-
combo.selectItems(newSelection);
1055+
combo.selectItems(newSelectionKeys);
10531056
fix.detectChanges();
10541057
expect(combo.selectedItems().length).toEqual(newSelection.length);
10551058
expect(combo.onSelectionChange.emit).toHaveBeenCalledTimes(1);
10561059
expect(combo.onSelectionChange.emit).toHaveBeenCalledWith({
10571060
oldSelection: oldSelection,
1058-
newSelection: newSelection,
1059-
added: [combo.data[1], combo.data[5], combo.data[6]],
1061+
newSelection: newSelectionKeys,
1062+
added: newSelectionKeys,
10601063
removed: [],
1064+
textValue: newSelection.map(entry => entry[combo.valueKey]).join(', '),
10611065
event: undefined,
10621066
cancel: false
10631067
});
10641068

10651069
let newItem = combo.data[3];
1066-
combo.selectItems([newItem]);
1067-
oldSelection = [...newSelection];
1068-
newSelection.push(newItem);
1070+
combo.selectItems([newItem[combo.valueKey]]);
1071+
oldSelection = [...newSelectionKeys];
1072+
newSelectionKeys.push(newItem[combo.valueKey]);
10691073
fix.detectChanges();
1070-
expect(combo.selectedItems().length).toEqual(newSelection.length);
1074+
expect(combo.selectedItems().length).toEqual(newSelectionKeys.length);
10711075
expect(combo.onSelectionChange.emit).toHaveBeenCalledTimes(2);
10721076
expect(combo.onSelectionChange.emit).toHaveBeenCalledWith({
10731077
oldSelection: oldSelection,
1074-
newSelection: newSelection,
1078+
newSelection: newSelectionKeys,
10751079
removed: [],
1076-
added: [combo.data[3]],
1080+
added: [newItem[combo.valueKey]],
1081+
textValue: newSelectionKeys.join(', '),
10771082
event: undefined,
10781083
cancel: false
10791084
});
10801085

1081-
oldSelection = [...newSelection];
1082-
newSelection = [combo.data[0]];
1083-
combo.selectItems(newSelection, true);
1086+
oldSelection = [...newSelectionKeys];
1087+
newSelectionKeys = [combo.data[0][combo.valueKey]];
1088+
combo.selectItems(newSelectionKeys, true);
10841089
fix.detectChanges();
1085-
expect(combo.selectedItems().length).toEqual(newSelection.length);
1090+
expect(combo.selectedItems().length).toEqual(newSelectionKeys.length);
10861091
expect(combo.onSelectionChange.emit).toHaveBeenCalledTimes(3);
10871092
expect(combo.onSelectionChange.emit).toHaveBeenCalledWith({
10881093
oldSelection: oldSelection,
1089-
newSelection: newSelection,
1094+
newSelection: newSelectionKeys,
10901095
removed: oldSelection,
1091-
added: [combo.data[0]],
1096+
added: [combo.data[0][combo.valueKey]],
1097+
textValue: combo.data[0][combo.valueKey],
10921098
event: undefined,
10931099
cancel: false
10941100
});
10951101

1096-
oldSelection = [...newSelection];
1102+
oldSelection = [...newSelectionKeys];
10971103
newSelection = [];
1098-
newItem = combo.data[0];
1104+
newItem = combo.data[0][combo.valueKey];
10991105
combo.deselectItems([newItem]);
11001106
fix.detectChanges();
11011107
expect(combo.selectedItems().length).toEqual(newSelection.length);
@@ -1104,7 +1110,8 @@ describe('igxCombo', () => {
11041110
expect(combo.onSelectionChange.emit).toHaveBeenCalledWith({
11051111
oldSelection: oldSelection,
11061112
newSelection: newSelection,
1107-
removed: [combo.data[0]],
1113+
removed: [newItem],
1114+
textValue: ``,
11081115
added: [],
11091116
event: undefined,
11101117
cancel: false
@@ -1422,11 +1429,12 @@ describe('igxCombo', () => {
14221429
const dropdown = combo.dropdown;
14231430
let timesFired = 1;
14241431
const mockEvent = new MouseEvent('click');
1425-
const eventParams = {
1432+
const eventParams: IComboSelectionChangeEventArgs = {
14261433
oldSelection: [],
14271434
newSelection: [],
14281435
added: [],
14291436
removed: [],
1437+
textValue: '',
14301438
event: mockEvent,
14311439
cancel: false
14321440
};
@@ -1446,12 +1454,14 @@ describe('igxCombo', () => {
14461454

14471455
eventParams.newSelection = [dropdown.items[3].value];
14481456
eventParams.added = [dropdown.items[3].value];
1457+
eventParams.textValue = dropdown.items[3].value;
14491458
verifyOnSelectionChangeEventIsFired(3);
14501459
timesFired++;
14511460

14521461
eventParams.oldSelection = [dropdown.items[3].value];
14531462
eventParams.newSelection = [dropdown.items[3].value, dropdown.items[7].value];
14541463
eventParams.added = [dropdown.items[7].value];
1464+
eventParams.textValue = `${dropdown.items[3].value}, ${dropdown.items[7].value}`;
14551465
verifyOnSelectionChangeEventIsFired(7);
14561466
timesFired++;
14571467

@@ -1460,6 +1470,7 @@ describe('igxCombo', () => {
14601470
eventParams.newSelection = [dropdown.items[3].value];
14611471
eventParams.added = [];
14621472
eventParams.removed = [dropdown.items[7].value];
1473+
eventParams.textValue = dropdown.items[3].value;
14631474
verifyOnSelectionChangeEventIsFired(7);
14641475
}));
14651476
it('Should be able to select item when in grouped state', fakeAsync(() => {
@@ -1593,56 +1604,67 @@ describe('igxCombo', () => {
15931604
fixture.detectChanges();
15941605
const combo = fixture.componentInstance.combo;
15951606
const selectionSpy = spyOn(fixture.componentInstance, 'onSelectionChange');
1596-
const expectedResults = {
1597-
newSelection: [combo.data[0]],
1607+
const expectedResults: IComboSelectionChangeEventArgs = {
1608+
newSelection: [combo.data[0][combo.valueKey]],
15981609
oldSelection: [],
1599-
added: [combo.data[0]],
1610+
added: [combo.data[0][combo.valueKey]],
16001611
removed: [],
16011612
event: undefined,
1613+
textValue: `${combo.data[0][combo.displayKey]}`,
16021614
cancel: false
16031615
};
1604-
combo.selectItems([combo.data[0]]);
1616+
combo.selectItems([combo.data[0][combo.valueKey]]);
16051617
expect(selectionSpy).toHaveBeenCalledWith(expectedResults);
16061618
Object.assign(expectedResults, {
16071619
newSelection: [],
1608-
oldSelection: [combo.data[0]],
1620+
oldSelection: [combo.data[0][combo.valueKey]],
16091621
added: [],
1610-
removed: [combo.data[0]]
1622+
textValue: '',
1623+
removed: [combo.data[0][combo.valueKey]]
16111624
});
1612-
combo.deselectItems([combo.data[0]]);
1625+
combo.deselectItems([combo.data[0][combo.valueKey]]);
16131626
expect(selectionSpy).toHaveBeenCalledWith(expectedResults);
16141627
});
16151628

16161629
it('Should properly emit added and removed values in change event - multiple values', () => {
16171630
const fixture = TestBed.createComponent(IgxComboSampleComponent);
16181631
fixture.detectChanges();
16191632
const combo = fixture.componentInstance.combo;
1633+
let oldSelection = [];
1634+
let newSelection = [combo.data[0], combo.data[1], combo.data[2]];
16201635
const selectionSpy = spyOn(fixture.componentInstance, 'onSelectionChange');
1621-
const expectedResults = {
1622-
newSelection: [combo.data[0], combo.data[1], combo.data[2]],
1623-
oldSelection: [],
1624-
added: [combo.data[0], combo.data[1], combo.data[2]],
1636+
const expectedResults: IComboSelectionChangeEventArgs = {
1637+
newSelection: newSelection.map(e => e[combo.valueKey]),
1638+
oldSelection,
1639+
added: newSelection.map(e => e[combo.valueKey]),
16251640
removed: [],
16261641
event: undefined,
1642+
textValue: `${newSelection.map(entry => entry[combo.displayKey]).join(', ')}`,
16271643
cancel: false
16281644
};
1629-
combo.selectItems([combo.data[0], combo.data[1], combo.data[2]]);
1645+
combo.selectItems(newSelection.map(e => e[combo.valueKey]));
16301646
expect(selectionSpy).toHaveBeenCalledWith(expectedResults);
1631-
combo.deselectItems([combo.data[0]]);
1647+
oldSelection = [...newSelection].map(e => e[combo.valueKey]);
1648+
newSelection = [combo.data[1], combo.data[2]];
1649+
combo.deselectItems([combo.data[0][combo.valueKey]]);
16321650
Object.assign(expectedResults, {
1633-
newSelection: [combo.data[1], combo.data[2]],
1634-
oldSelection: [combo.data[0], combo.data[1], combo.data[2]],
1651+
newSelection: newSelection.map(e => e[combo.valueKey]),
1652+
oldSelection,
16351653
added: [],
1636-
removed: [combo.data[0]]
1654+
textValue: newSelection.map(e => e[combo.displayKey]).join(', '),
1655+
removed: [combo.data[0][combo.valueKey]]
16371656
});
1657+
oldSelection = [...newSelection].map(e => e[combo.valueKey]);
1658+
newSelection = [combo.data[4], combo.data[5], combo.data[6]];
16381659
expect(selectionSpy).toHaveBeenCalledWith(expectedResults);
16391660
Object.assign(expectedResults, {
1640-
newSelection: [combo.data[4], combo.data[5], combo.data[6]],
1641-
oldSelection: [combo.data[1], combo.data[2]],
1642-
added: [combo.data[4], combo.data[5], combo.data[6]],
1643-
removed: [combo.data[1], combo.data[2]]
1661+
newSelection: newSelection.map(e => e[combo.valueKey]),
1662+
oldSelection,
1663+
added: newSelection.map(e => e[combo.valueKey]),
1664+
textValue: newSelection.map(e => e[combo.displayKey]).join(', '),
1665+
removed: oldSelection
16441666
});
1645-
combo.selectItems([combo.data[4], combo.data[5], combo.data[6]], true);
1667+
combo.selectItems(newSelection.map(e => e[combo.valueKey]), true);
16461668
expect(selectionSpy).toHaveBeenCalledWith(expectedResults);
16471669
});
16481670
});

projects/igniteui-angular/src/lib/combo/combo.component.ts

+19-1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ export interface IComboSelectionChangeEventArgs extends CancelableEventArgs, IBa
9191
added: any[];
9292
/** An array containing the values that will be removed from the selection (if any) */
9393
removed: any[];
94+
/** The text that will be displayed in the combo text box
95+
* If the combo is **remote**, this will be empty
96+
*/
97+
textValue: string;
9498
/** The user interaction that triggered the selection change */
9599
event?: Event;
96100
}
@@ -1382,12 +1386,15 @@ export class IgxComboComponent extends DisplayDensityBase implements IgxComboBas
13821386
protected setSelection(newSelection: Set<any>, event?: Event): void {
13831387
const removed = diffInSets(this.selection.get(this.id), newSelection);
13841388
const added = diffInSets(newSelection, this.selection.get(this.id));
1389+
const newSelectionAsArray = Array.from(newSelection);
1390+
const text = this.concatTextValue(newSelectionAsArray);
13851391
const args: IComboSelectionChangeEventArgs = {
1386-
newSelection: Array.from(newSelection),
1392+
newSelection: newSelectionAsArray,
13871393
oldSelection: Array.from(this.selection.get(this.id) || []),
13881394
added,
13891395
removed,
13901396
event,
1397+
textValue: text,
13911398
cancel: false
13921399
};
13931400
this.onSelectionChange.emit(args);
@@ -1415,6 +1422,17 @@ export class IgxComboComponent extends DisplayDensityBase implements IgxComboBas
14151422
}
14161423
}
14171424

1425+
/** Returns a string that should be populated in the combo's text box
1426+
* If the combo is remote, returns an empty string (as the items may not be loaded yet)
1427+
*/
1428+
private concatTextValue(selection: any[]): string {
1429+
if (this.isRemote) { return ''; }
1430+
const value = this.displayKey !== null && this.displayKey !== undefined ?
1431+
this.convertKeysToItems(selection).map(entry => entry[this.displayKey]).join(', ') :
1432+
selection.join(', ');
1433+
return value;
1434+
}
1435+
14181436
/** if there is a valueKey - map the keys to data items, else - just return the keys */
14191437
private convertKeysToItems(keys: any[]) {
14201438
if (this.comboAPI.valueKey === null) {

0 commit comments

Comments
 (0)