Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: IgniteUI/igniteui-angular
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 14.2.0
Choose a base ref
...
head repository: IgniteUI/igniteui-angular
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 14.2.1
Choose a head ref
  • 1 commit
  • 12 files changed
  • 3 contributors

Commits on Oct 6, 2022

  1. Select falsy values via ngModel - master (#12102)

    * test(simple-combo): should select falsy values with "writeValue" method
    
    * fix(simple-combo): select falsy values with "writeValue" method
    
    * test(selectionService): should add items with falsy itemID except undefined
    
    * fix(selectionService): add items with falsy itemID except undefined
    
    * test(combos): should select falsy values except "undefined"
    
    * fix(combos): select falsy values except "undefined"
    
    * fix(combos): display and select "null" in dropdown
    
    * test(selectionService): removing an outdated test
    
    * fix(selectionService): removing throw error check
    
    * fix(combos): additional checks for nullish values
    
    * chore(combos): add comment for template check
    
    * chore(remoteNWindService): remove debugger
    
    * test(combos): should remove undefined from array of primitive data
    
    * fix(combos): remove undefined from array of primitive data
    
    * fix(combos): remove undefined in data setter
    
    * fix(simple-combo): show all items in dropdown
    
    * chore(combo-pipes): add comment for grouping pipe
    
    * test(simple-combo): should not select null, undefined, '' in template form
    
    * fix(simple-combo): not select null, undefined, '' in template form
    
    * fix(simple-combo): not select null, undefined, '' in reactive form
    
    Co-authored-by: Teodosia Hristodorova <52423497+teodosiah@users.noreply.github.com>
    Co-authored-by: Stamen Stoychev <sstoychev@infragistics.com>
    3 people authored Oct 6, 2022

    Verified

    This commit was signed with the committer’s verified signature. The key has expired.
    suzuki-shunsuke Shunsuke Suzuki
    Copy the full SHA
    e05b38d View commit details
Original file line number Diff line number Diff line change
@@ -113,7 +113,7 @@ export class IgxComboDropDownComponent extends IgxDropDownComponent implements I
* @hidden
*/
public navigateFirst() {
this.navigateItem(this.virtDir.igxForOf.findIndex(e => !e.isHeader));
this.navigateItem(this.virtDir.igxForOf.findIndex(e => !e?.isHeader));
this.combo.setActiveDescendant();
}

4 changes: 3 additions & 1 deletion projects/igniteui-angular/src/lib/combo/combo.api.ts
Original file line number Diff line number Diff line change
@@ -41,7 +41,9 @@ export class IgxComboAPIService {

public set_selected_item(itemID: any, event?: Event): void {
const selected = this.combo.isItemSelected(itemID);

if (itemID === undefined) {
return;
}
if (!selected) {
this.combo.select([itemID], false, event);
} else {
18 changes: 17 additions & 1 deletion projects/igniteui-angular/src/lib/combo/combo.common.ts
Original file line number Diff line number Diff line change
@@ -307,7 +307,13 @@ export abstract class IgxComboBaseDirective extends DisplayDensityBase implement
return this._data;
}
public set data(val: any[] | null) {
this._data = (val) ? val : [];
// igxFor directive ignores undefined values
// if the combo uses simple data and filtering is applied
// an error will occur due to the mismatch of the length of the data
// this can occur during filtering for the igx-combo and
// during filtering & selection for the igx-simple-combo
// since the simple combo's input is both a container for the selection and a filter
this._data = (val) ? val.filter(x => x !== undefined) : [];
}

/**
@@ -1297,6 +1303,16 @@ export abstract class IgxComboBaseDirective extends DisplayDensityBase implement
return Object.keys(this._remoteSelection).map(e => this._remoteSelection[e]).join(', ');
}

protected get required(): boolean {
if (this.ngControl && this.ngControl.control && this.ngControl.control.validator) {
// Run the validation with empty object to check if required is enabled.
const error = this.ngControl.control.validator({} as AbstractControl);
return error && error.required;
}

return false;
}

public abstract get filteredData(): any[] | null;
public abstract set filteredData(val: any[] | null);

7 changes: 4 additions & 3 deletions projects/igniteui-angular/src/lib/combo/combo.component.html
Original file line number Diff line number Diff line change
@@ -60,14 +60,15 @@
| comboFiltering:filterValue:displayKey:filteringOptions:filterFunction
| comboGrouping:groupKey:valueKey:groupSortingDirection;
index as rowIndex; containerSize: itemsMaxHeight; scrollOrientation: 'vertical'; itemSize: itemHeight"
[value]="item" [isHeader]="item.isHeader" [index]="rowIndex" [role]="item.isHeader? 'group' : 'option'">
<ng-container *ngIf="item.isHeader">
[value]="item" [isHeader]="item?.isHeader" [index]="rowIndex" [role]="item?.isHeader? 'group' : 'option'">
<ng-container *ngIf="item?.isHeader">
<ng-container
*ngTemplateOutlet="headerItemTemplate ? headerItemTemplate : headerItemBase;
context: {$implicit: item, data: data, valueKey: valueKey, groupKey: groupKey, displayKey: displayKey}">
</ng-container>
</ng-container>
<ng-container *ngIf="!item.isHeader">
<!-- if item is 'null' it should be displayed and !!(item?.isHeader) would resolve it to 'false' and not display it -->
<ng-container *ngIf="!item?.isHeader">
<ng-container #listItem
*ngTemplateOutlet="template; context: {$implicit: item, data: data, valueKey: valueKey, displayKey: displayKey};">
</ng-container>
61 changes: 53 additions & 8 deletions projects/igniteui-angular/src/lib/combo/combo.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1225,6 +1225,14 @@ describe('igxCombo', () => {
const comboData = combo.data;
expect(comboData).toEqual(data);
});
it('should remove undefined from array of primitive data', () => {
fixture = TestBed.createComponent(IgxComboInContainerTestComponent);
fixture.detectChanges();
combo = fixture.componentInstance.combo;
combo.data = ['New York', 'Sofia', undefined, 'Istanbul','Paris'];

expect(combo.data).toEqual(['New York', 'Sofia', 'Istanbul','Paris']);
});
it('should bind combo data to array of objects', () => {
fixture = TestBed.createComponent(IgxComboSampleComponent);
fixture.detectChanges();
@@ -2087,16 +2095,16 @@ describe('igxCombo', () => {
expect(combo.selection.length).toEqual(0);
expect(combo.selectionChanging.emit).toHaveBeenCalledTimes(0);
});
it('should select unique falsy item values', () => {
it('should select falsy values except "undefined"', () => {
combo.valueKey = 'value';
combo.displayKey = 'field';
combo.data = [
{ field: '0', value: 0 },
{ field: 'false', value: false },
{ field: '', value: '' },
{ field: 'undefined', value: undefined },
{ field: 'null', value: null },
{ field: 'NaN', value: NaN },
{ field: 'undefined', value: undefined },
];

combo.open();
@@ -2136,8 +2144,8 @@ describe('igxCombo', () => {

item4.triggerEventHandler('click', UIInteractions.getMouseEvent('click'));
fixture.detectChanges();
expect(combo.value).toBe('0, false, , undefined');
expect(combo.selection).toEqual([ 0, false, '', undefined ]);
expect(combo.value).toBe('0, false, , null');
expect(combo.selection).toEqual([ 0, false, '', null ]);

combo.open();
fixture.detectChanges();
@@ -2146,8 +2154,8 @@ describe('igxCombo', () => {

item5.triggerEventHandler('click', UIInteractions.getMouseEvent('click'));
fixture.detectChanges();
expect(combo.value).toBe('0, false, , undefined, null');
expect(combo.selection).toEqual([ 0, false, '', undefined, null ]);
expect(combo.value).toBe('0, false, , null, NaN');
expect(combo.selection).toEqual([ 0, false, '', null, NaN ]);

combo.open();
fixture.detectChanges();
@@ -2156,8 +2164,45 @@ describe('igxCombo', () => {

item6.triggerEventHandler('click', UIInteractions.getMouseEvent('click'));
fixture.detectChanges();
expect(combo.value).toBe('0, false, , undefined, null, NaN');
expect(combo.selection).toEqual([ 0, false, '', undefined, null, NaN ]);
expect(combo.value).toBe('0, false, , null, NaN');
expect(combo.selection).toEqual([ 0, false, '', null, NaN ]);
});
it('should select falsy values except "undefined" with "writeValue" method', () => {
combo.valueKey = 'value';
combo.displayKey = 'field';
combo.data = [
{ field: '0', value: 0 },
{ field: 'false', value: false },
{ field: 'empty', value: '' },
{ field: 'null', value: null },
{ field: 'NaN', value: NaN },
{ field: 'undefined', value: undefined },
];

combo.writeValue([0]);
expect(combo.selection).toEqual([0]);
expect(combo.value).toBe('0');

combo.writeValue([false]);
expect(combo.selection).toEqual([false]);
expect(combo.value).toBe('false');

combo.writeValue(['']);
expect(combo.selection).toEqual(['']);
expect(combo.value).toBe('empty');

combo.writeValue([null]);
expect(combo.selection).toEqual([null]);
expect(combo.value).toBe('null');

combo.writeValue([NaN]);
expect(combo.selection).toEqual([NaN]);
expect(combo.value).toBe('NaN');

// should not select undefined
combo.writeValue([undefined]);
expect(combo.selection).toEqual([]);
expect(combo.value).toBe('');
});
it('should prevent selection when selectionChanging is cancelled', () => {
spyOn(combo.selectionChanging, 'emit').and.callFake((event: IComboSelectionChangingEventArgs) => event.cancel = true);
5 changes: 4 additions & 1 deletion projects/igniteui-angular/src/lib/combo/combo.component.ts
Original file line number Diff line number Diff line change
@@ -235,7 +235,7 @@ export class IgxComboComponent extends IgxComboBaseDirective implements AfterVie
* @hidden @internal
*/
public writeValue(value: any[]): void {
const selection = Array.isArray(value) ? value : [];
const selection = Array.isArray(value) ? value.filter(x => x !== undefined) : [];
const oldSelection = this.selection;
this.selectionService.select_items(this.id, selection, true);
this.cdr.markForCheck();
@@ -355,6 +355,9 @@ export class IgxComboComponent extends IgxComboBaseDirective implements AfterVie
* ```
*/
public setSelectedItem(itemID: any, select = true, event?: Event): void {
if (itemID === undefined) {
return;
}
if (select) {
this.select([itemID], false, event);
} else {
5 changes: 3 additions & 2 deletions projects/igniteui-angular/src/lib/combo/combo.pipes.ts
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@ export class IgxComboGroupingPipe implements PipeTransform {
constructor(@Inject(IGX_COMBO_COMPONENT) public combo: IgxComboBase) { }

public transform(collection: any[], groupKey: any, valueKey: any, sortingDirection: SortingDirection) {
// TODO: should filteredData be changed here?
this.combo.filteredData = collection;
if ((!groupKey && groupKey !== 0) || !collection.length) {
return collection;
@@ -74,7 +75,7 @@ function defaultFilterFunction (collection: any[], searchValue: any, filteringOp
e[filteringOptions.filteringKey]?.toString().toLowerCase().includes(searchTerm));
} else {
return collection.filter(e => filteringOptions.caseSensitive ?
e.includes(searchTerm) :
e.toString().toLowerCase().includes(searchTerm));
e?.includes(searchTerm) :
e?.toString().toLowerCase().includes(searchTerm));
}
}
11 changes: 4 additions & 7 deletions projects/igniteui-angular/src/lib/core/selection.spec.ts
Original file line number Diff line number Diff line change
@@ -23,13 +23,10 @@ describe('IgxSelectionAPIService', () => {
const selection3 = service.add_item(componentId, null);
expect(selection3.has(null)).toBe(true);

const selection4 = service.add_item(componentId, undefined);
expect(selection4.has(undefined)).toBe(true);
const selection4 = service.add_item(componentId, '');
expect(selection4.has('')).toBe(true);

const selection5 = service.add_item(componentId, '');
expect(selection5.has('')).toBe(true);

const selection6 = service.add_item(componentId, NaN);
expect(selection6.has(NaN)).toBe(true);
const selection5 = service.add_item(componentId, NaN);
expect(selection5.has(NaN)).toBe(true);
});
});
Original file line number Diff line number Diff line change
@@ -55,19 +55,20 @@
[tabindex]="dropdown.collapsed ? -1 : 0" [attr.id]="dropdown.id"
[attr.aria-activedescendant]="this.activeDescendant"
(focus)="dropdown.onFocus()" (keydown)="handleItemKeyDown($event)">
<igx-combo-item [role]="item.isHeader? 'group' : 'option'" [singleMode]="true"
<igx-combo-item [role]="item?.isHeader? 'group' : 'option'" [singleMode]="true"
[itemHeight]="itemHeight" (click)="handleItemClick()" *igxFor="let item of data
| comboFiltering:filterValue:displayKey:filteringOptions:filterFunction
| comboGrouping:groupKey:valueKey:groupSortingDirection;
index as rowIndex; containerSize: itemsMaxHeight; scrollOrientation: 'vertical'; itemSize: itemHeight"
[value]="item" [isHeader]="item.isHeader" [index]="rowIndex">
<ng-container *ngIf="item.isHeader">
[value]="item" [isHeader]="item?.isHeader" [index]="rowIndex">
<ng-container *ngIf="item?.isHeader">
<ng-container
*ngTemplateOutlet="headerItemTemplate ? headerItemTemplate : headerItemBase;
context: {$implicit: item, data: data, valueKey: valueKey, groupKey: groupKey, displayKey: displayKey}">
</ng-container>
</ng-container>
<ng-container *ngIf="!item.isHeader">
<!-- if item is 'null' it should be displayed and !!(item?.isHeader) would resolve it to 'false' and not display it -->
<ng-container *ngIf="!item?.isHeader">
<ng-container #listItem
*ngTemplateOutlet="template; context: {$implicit: item, data: data, valueKey: valueKey, displayKey: displayKey};">
</ng-container>
Loading