diff --git a/projects/igniteui-angular/src/lib/combo/combo.api.ts b/projects/igniteui-angular/src/lib/combo/combo.api.ts index 45b016daf4f..5f946ac3bbf 100644 --- a/projects/igniteui-angular/src/lib/combo/combo.api.ts +++ b/projects/igniteui-angular/src/lib/combo/combo.api.ts @@ -41,7 +41,7 @@ export class IgxComboAPIService { public set_selected_item(itemID: any, event?: Event): void { const selected = this.combo.isItemSelected(itemID); - if (itemID === null || itemID === undefined) { + if (!itemID && itemID !== 0) { return; } if (!selected) { diff --git a/projects/igniteui-angular/src/lib/combo/combo.component.ts b/projects/igniteui-angular/src/lib/combo/combo.component.ts index ed3653bc480..dd31509b332 100644 --- a/projects/igniteui-angular/src/lib/combo/combo.component.ts +++ b/projects/igniteui-angular/src/lib/combo/combo.component.ts @@ -28,7 +28,7 @@ import { IgxDropDownModule } from '../drop-down/public_api'; import { IgxInputGroupModule } from '../input-group/input-group.component'; import { IgxComboItemComponent } from './combo-item.component'; import { IgxComboDropDownComponent } from './combo-dropdown.component'; -import { IgxComboFilteringPipe, IgxComboGroupingPipe } from './combo.pipes'; +import { IgxComboCleanPipe, IgxComboFilteringPipe, IgxComboGroupingPipe } from './combo.pipes'; import { DisplayDensityToken, IDisplayDensityOptions } from '../core/density'; import { IGX_COMBO_COMPONENT, IgxComboBaseDirective } from './combo.common'; import { IgxComboAddItemComponent } from './combo-add-item.component'; @@ -448,6 +448,7 @@ export class IgxComboComponent extends IgxComboBaseDirective implements AfterVie IgxComboDropDownComponent, IgxComboEmptyDirective, IgxComboFilteringPipe, + IgxComboCleanPipe, IgxComboFooterDirective, IgxComboGroupingPipe, IgxComboHeaderDirective, @@ -464,6 +465,7 @@ export class IgxComboComponent extends IgxComboBaseDirective implements AfterVie IgxComboDropDownComponent, IgxComboEmptyDirective, IgxComboFilteringPipe, + IgxComboCleanPipe, IgxComboFooterDirective, IgxComboGroupingPipe, IgxComboHeaderDirective, diff --git a/projects/igniteui-angular/src/lib/combo/combo.pipes.ts b/projects/igniteui-angular/src/lib/combo/combo.pipes.ts index eb24ebbf884..eda97385476 100644 --- a/projects/igniteui-angular/src/lib/combo/combo.pipes.ts +++ b/projects/igniteui-angular/src/lib/combo/combo.pipes.ts @@ -5,10 +5,17 @@ import { IGX_COMBO_COMPONENT, IgxComboBase } from './combo.common'; import { DefaultSortingStrategy, SortingDirection } from '../data-operations/sorting-strategy'; import { IComboFilteringOptions } from './combo.component'; +/** @hidden */ +@Pipe({ + name: 'comboClean' +}) +export class IgxComboCleanPipe implements PipeTransform { + public transform(collection: any[]) { + return collection.filter(e => !!e); + } +} -/** - * @hidden - */ +/** @hidden */ @Pipe({ name: 'comboFiltering' }) @@ -23,8 +30,8 @@ export class IgxComboFilteringPipe implements PipeTransform { } else { const searchTerm = filteringOptions.caseSensitive ? searchValue.trim() : searchValue.toLowerCase().trim(); if (displayKey != null) { - return collection.filter(e => filteringOptions.caseSensitive ? e[displayKey].includes(searchTerm) : - e[displayKey].toString().toLowerCase().includes(searchTerm)); + return collection.filter(e => filteringOptions.caseSensitive ? e[displayKey]?.includes(searchTerm) : + e[displayKey]?.toString().toLowerCase().includes(searchTerm)); } else { return collection.filter(e => filteringOptions.caseSensitive ? e.includes(searchTerm) : e.toString().toLowerCase().includes(searchTerm)); @@ -33,9 +40,7 @@ export class IgxComboFilteringPipe implements PipeTransform { } } -/** - * @hidden - */ +/** @hidden */ @Pipe({ name: 'comboGrouping' }) export class IgxComboGroupingPipe implements PipeTransform { diff --git a/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.html b/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.html index 0f3779dbf34..6e87bfbc38d 100644 --- a/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.html +++ b/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.html @@ -51,6 +51,7 @@ [tabindex]="dropdown.collapsed ? -1 : 0" role="listbox" [attr.id]="dropdown.id" (keydown)="handleItemKeyDown($event)"> { expect(combo.dropdown.closing.emit).toHaveBeenCalledTimes(1); expect(combo.value).toBeFalsy(); }); + + it('should empty and invalid item values', () => { + combo.valueKey = 'key'; + combo.displayKey = 'value'; + combo.data = [ + { key: 1, value: null }, + { key: 2, value: 'val2' }, + { key: 3, value: '' }, + { key: 4, value: undefined }, + ]; + + combo.open(); + fixture.detectChanges(); + const item1 = fixture.debugElement.query(By.css(`.${CSS_CLASS_DROPDOWNLISTITEM}`)); + expect(item1).toBeDefined(); + + item1.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); + fixture.detectChanges(); + expect(combo.value).toBe(null); + + combo.open(); + fixture.detectChanges(); + const item2 = fixture.debugElement.queryAll(By.css(`.${CSS_CLASS_DROPDOWNLISTITEM}`))[1]; + expect(item2).toBeDefined(); + + item2.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); + fixture.detectChanges(); + expect(combo.value).toBe('val2'); + + combo.open(); + fixture.detectChanges(); + const item3 = fixture.debugElement.queryAll(By.css(`.${CSS_CLASS_DROPDOWNLISTITEM}`))[2]; + expect(item3).toBeDefined(); + + item3.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); + fixture.detectChanges(); + expect(combo.value).toBe(''); + + combo.open(); + fixture.detectChanges(); + const item5 = fixture.debugElement.queryAll(By.css(`.${CSS_CLASS_DROPDOWNLISTITEM}`))[3]; + expect(item5).toBeDefined(); + + item5.triggerEventHandler('click', UIInteractions.getMouseEvent('click')); + fixture.detectChanges(); + expect(combo.value).toBe(undefined); + }); }); describe('Display density', () => { diff --git a/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.ts b/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.ts index 00b8f2aac0a..a80e70e5c66 100644 --- a/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.ts +++ b/projects/igniteui-angular/src/lib/simple-combo/simple-combo.component.ts @@ -378,6 +378,10 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co protected findMatch = (element: any): boolean => { const value = this.displayKey ? element[this.displayKey] : element; + if (value === null || value === undefined || value === '') { + // we can accept null, undefined and empty strings as empty display values + return true; + } const searchValue = this.searchValue || this.comboInput.value; return !!searchValue && value.toString().toLowerCase().includes(searchValue.trim().toLowerCase()); }; @@ -411,7 +415,7 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co } } - protected createDisplayText(newSelection: any[], oldSelection: any[]): any { + protected createDisplayText(newSelection: any[], oldSelection: any[]): string { if (this.isRemote) { return this.getRemoteSelection(newSelection, oldSelection); } @@ -452,7 +456,8 @@ export class IgxSimpleComboComponent extends IgxComboBaseDirective implements Co return null; } - return this.displayKey ? element[this.displayKey] : element; + const elementVal = this.displayKey ? element[this.displayKey] : element; + return (elementVal === 0 ? '0' : elementVal) || ''; } private clearAndClose(): void {