Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ export class IgxComboItemComponent extends IgxDropDownItemComponent {
/** @hidden @internal */
@HostBinding('style.height.rem')
public get _itemHeightToRem() {
return rem(this.itemHeight);
if (this.itemHeight) {
return rem(this.itemHeight);
}
}

@HostBinding('attr.aria-label')
Expand Down
49 changes: 20 additions & 29 deletions projects/igniteui-angular/src/lib/combo/combo.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ import { IComboItemAdditionEvent, IComboSearchInputEventArgs } from './public_ap
import { ComboResourceStringsEN, IComboResourceStrings } from '../core/i18n/combo-resources';
import { getCurrentResourceStrings } from '../core/i18n/resources';
import { DOCUMENT } from '@angular/common';
import { Size } from '../grids/common/enums';
import { isEqual } from 'lodash-es';

export const IGX_COMBO_COMPONENT = /*@__PURE__*/new InjectionToken<IgxComboBase>('IgxComboComponentToken');
Expand Down Expand Up @@ -82,19 +81,6 @@ export interface IgxComboBase {

let NEXT_ID = 0;

/**
* @hidden
* The default number of items that should be in the combo's
* drop-down list if no `[itemsMaxHeight]` is specified
*/
const itemsInContainer = 10; // TODO: make private readonly

/** @hidden @internal */
const ItemHeights = {
"3": 40,
"2": 32,
"1": 28
};

/** @hidden @internal */
export const enum DataTypes {
Expand Down Expand Up @@ -234,8 +220,8 @@ export abstract class IgxComboBaseDirective implements IgxComboBase, AfterViewCh
*/
@Input()
public get itemsMaxHeight(): number {
if (this._itemsMaxHeight === null || this._itemsMaxHeight === undefined) {
return this.itemHeight * itemsInContainer;
if (this.itemHeight && !this._itemsMaxHeight) {
return this.itemHeight * this.itemsInContainer;
}
return this._itemsMaxHeight;
}
Expand All @@ -246,15 +232,9 @@ export abstract class IgxComboBaseDirective implements IgxComboBase, AfterViewCh

/** @hidden */
public get itemsMaxHeightInRem() {
return rem(this.itemsMaxHeight);
}

/**
* @hidden
* @internal
*/
public get comboSize(): Size {
return this.computedStyles?.getPropertyValue('--ig-size') || Size.Large;
if (this.itemsMaxHeight) {
return rem(this.itemsMaxHeight);
}
}

/**
Expand All @@ -272,9 +252,6 @@ export abstract class IgxComboBaseDirective implements IgxComboBase, AfterViewCh
*/
@Input()
public get itemHeight(): number {
if (this._itemHeight === null || this._itemHeight === undefined) {
return ItemHeights[this.comboSize];
}
return this._itemHeight;
}

Expand Down Expand Up @@ -943,6 +920,9 @@ export abstract class IgxComboBaseDirective implements IgxComboBase, AfterViewCh
public set filteringOptions(value: IComboFilteringOptions) {
this._filteringOptions = value;
}

protected containerSize = undefined;
protected itemSize = undefined;
protected _data = [];
protected _value = [];
protected _displayValue = '';
Expand All @@ -963,12 +943,13 @@ export abstract class IgxComboBaseDirective implements IgxComboBase, AfterViewCh
private _id: string = `igx-combo-${NEXT_ID++}`;
private _type = null;
private _dataType = '';
private _itemHeight = null;
private _itemHeight = undefined;
private _itemsMaxHeight = null;
private _overlaySettings: OverlaySettings;
private _groupSortingDirection: SortingDirection = SortingDirection.Asc;
private _filteringOptions: IComboFilteringOptions;
private _defaultFilteringOptions: IComboFilteringOptions = { caseSensitive: false };
private itemsInContainer = 10;

public abstract dropdown: IgxComboDropDownComponent;
public abstract selectionChanging: EventEmitter<any>;
Expand Down Expand Up @@ -1029,6 +1010,16 @@ export abstract class IgxComboBaseDirective implements IgxComboBase, AfterViewCh
const eventArgs: IForOfState = Object.assign({}, e, { owner: this });
this.dataPreLoad.emit(eventArgs);
});
this.dropdown?.opening.subscribe((_args: IBaseCancelableBrowserEventArgs) => {
// calculate the container size and item size based on the sizes from the DOM
const dropdownContainerHeight = this.dropdownContainer.nativeElement.getBoundingClientRect().height;
if (dropdownContainerHeight) {
this.containerSize = parseFloat(dropdownContainerHeight);
}
if (this.dropdown.children?.first) {
this.itemSize = this.dropdown.children.first.element.nativeElement.getBoundingClientRect().height;
}
});
}

/** @hidden @internal */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
<igx-combo-item [itemHeight]="itemHeight" *igxFor="let item of data
| comboFiltering:filterValue:displayKey:filteringOptions:filterFunction:disableFiltering
| comboGrouping:groupKey:valueKey:groupSortingDirection:compareCollator;
index as rowIndex; containerSize: itemsMaxHeight; scrollOrientation: 'vertical'; itemSize: itemHeight"
index as rowIndex; initialChunkSize: 10; containerSize: itemsMaxHeight || containerSize; itemSize: itemHeight || itemSize, scrollOrientation: 'vertical';"
[value]="item" [isHeader]="item?.isHeader" [index]="rowIndex" [role]="item?.isHeader? 'group' : 'option'">
<ng-container *ngIf="item?.isHeader">
<ng-container
Expand Down
28 changes: 3 additions & 25 deletions projects/igniteui-angular/src/lib/combo/combo.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1025,8 +1025,6 @@ describe('igxCombo', () => {
expect(combo.displayKey).toEqual('field');
expect(combo.groupKey).toEqual('region');
expect(combo.width).toEqual('400px');
expect(combo.itemsMaxHeight).toEqual(320);
expect(combo.itemHeight).toEqual(32);
expect(combo.placeholder).toEqual('Location');
expect(combo.disableFiltering).toEqual(false);
expect(combo.allowCustomValues).toEqual(false);
Expand Down Expand Up @@ -1125,9 +1123,7 @@ describe('igxCombo', () => {
const dropdownList = fixture.debugElement.query(By.css(`.${CSS_CLASS_CONTENT}`));

const verifyDropdownItemHeight = () => {
expect(combo.itemHeight).toEqual(itemHeight);
expect(dropdownItems[0].nativeElement.clientHeight).toEqual(itemHeight);
expect(combo.itemsMaxHeight).toEqual(itemMaxHeight);
expect(dropdownList.nativeElement.clientHeight).toEqual(itemMaxHeight);
};
verifyDropdownItemHeight();
Expand Down Expand Up @@ -1764,11 +1760,10 @@ describe('igxCombo', () => {
});
it('should focus item when onFocus and onBlur are called', () => {
expect(dropdown.focusedItem).toEqual(null);
expect(dropdown.items.length).toEqual(9);
dropdown.toggle();
fixture.detectChanges();
expect(dropdown.items).toBeDefined();
expect(dropdown.items.length).toBeTruthy();
expect(dropdown.items.length).toEqual(9);
dropdown.onFocus();
expect(dropdown.focusedItem).toEqual(dropdown.items[0]);
expect(dropdown.focusedItem.focused).toEqual(true);
Expand Down Expand Up @@ -2015,7 +2010,8 @@ describe('igxCombo', () => {
expect(combo.dropdown.onToggleOpened).toHaveBeenCalledTimes(1);
let vContainerScrollHeight = virtDir.getScroll().scrollHeight;
expect(virtDir.getScroll().scrollTop).toEqual(0);
expect(vContainerScrollHeight).toBeGreaterThan(combo.itemHeight);
const itemHeight = parseFloat(combo.dropdown.children.first.element.nativeElement.getBoundingClientRect().height);
expect(vContainerScrollHeight).toBeGreaterThan(itemHeight);
virtDir.getScroll().scrollTop = Math.floor(vContainerScrollHeight / 2);
await firstValueFrom(combo.virtualScrollContainer.chunkLoad);
fixture.detectChanges();
Expand Down Expand Up @@ -3573,24 +3569,6 @@ describe('igxCombo', () => {
}));
});
});
describe('Display density', () => {
beforeEach(() => {
fixture = TestBed.createComponent(IgxComboSampleComponent);
fixture.detectChanges();
combo = fixture.componentInstance.combo;
});
it('should scale items container depending on size (itemHeight * 10)', () => {
combo.toggle();
fixture.detectChanges();
expect(combo.itemsMaxHeight).toEqual(320);
fixture.componentInstance.size = 'small';
fixture.detectChanges();
expect(combo.itemsMaxHeight).toEqual(280);
fixture.componentInstance.size = 'large';
fixture.detectChanges();
expect(combo.itemsMaxHeight).toEqual(400);
});
});
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@
%igx-combo__content {
position: relative;
overflow: hidden;
max-height: calc(var(--size) * 10);
Copy link
Collaborator

@simeonoff simeonoff Jan 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the baseline assumption of 10 items as the initial chunk size, right? I wonder if we should make this as a CSS variable bound to a property in the business logic, i.e. the initialChunkSize?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, exactly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the thing is that if we set a HostBinding on the combo then we expect to inherit the variable and use it in the igx-combo__content class. However, the overlay service move the dropdown container to a div that is not in the hierarchy of the combo, thus we cannot use that bound variable.


&:focus {
outline: transparent;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,16 @@ describe('IgxForOf directive -', () => {
await wait(200);
expect(cache).toEqual([130, 100, 100, 100, 100, 100, 100, 130, 130, 130]);
});

it('should render no more that initial chunk size elements when set if no containerSize', () => {
fix.componentInstance.height = undefined;
fix.componentInstance.initialChunkSize = 3;
fix.detectChanges();
expect(displayContainer).not.toBeNull();
expect(verticalScroller).not.toBeNull();
expect(horizontalScroller).toBeNull();
expect(displayContainer.children.length).toBe(3);
});
});

describe('vertical virtual component no data', () => {
Expand Down Expand Up @@ -407,7 +417,6 @@ describe('IgxForOf directive -', () => {
rowsRendered = displayContainer.querySelectorAll('div');
expect(rowsRendered.length).not.toBe(0);
});

});

describe('vertical and horizontal virtual component', () => {
Expand Down Expand Up @@ -1471,7 +1480,8 @@ export class VirtualComponent {
<ng-template #scrollContainer igxForTest let-rowData [igxForOf]="data"
[igxForScrollOrientation]="'vertical'"
[igxForContainerSize]='height'
[igxForItemSize]='itemSize'>
[igxForItemSize]='itemSize'
[igxForInitialChunkSize]='initialChunkSize'>
<div [style.display]="'flex'"
[style.height]="rowData.height || itemSize || '50px'"
[style.margin-top]="rowData.margin || '0px'">
Expand Down Expand Up @@ -1499,6 +1509,7 @@ export class VerticalVirtualComponent extends VirtualComponent {
];
public override data = [];
public itemSize = '50px';
public initialChunkSize;
}

@Component({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,14 @@ export class IgxForOfDirective<T, U extends T[] = T[]> extends IgxForOfToken<T,U
@Input()
public igxForContainerSize: any;

/**
* @hidden
* @internal
* Initial chunk size if no container size is passed. If container size is passed then the igxForOf calculates its chunk size
*/
@Input()
public igxForInitialChunkSize: any;

/**
* Sets the px-affixed size of the item along the axis of scrolling.
* For "horizontal" orientation this value is the width of the column and for "vertical" is the height or the row.
Expand Down Expand Up @@ -1207,7 +1215,7 @@ export class IgxForOfDirective<T, U extends T[] = T[]> extends IgxForOfToken<T,U
}
} else {
if (this.igxForOf) {
chunkSize = this.igxForOf.length;
chunkSize = Math.min(this.igxForInitialChunkSize || this.igxForOf.length, this.igxForOf.length);
}
}
return chunkSize;
Expand Down
14 changes: 7 additions & 7 deletions projects/igniteui-angular/src/lib/services/overlay/overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,8 +346,13 @@ export class IgxOverlayService implements OnDestroy {
info.hook = this.placeElementHook(info.elementRef.nativeElement);
const elementRect = info.elementRef.nativeElement.getBoundingClientRect();
info.initialSize = { width: elementRect.width, height: elementRect.height };
this.addComponentSize(info);
// Get the size before moving the container into the overlay so that it does not forget about inherited styles.
this.getComponentSize(info);
this.moveElementToOverlay(info);
// Update the container size after moving if there is size.
if (info.size) {
info.elementRef.nativeElement.parentElement.style.setProperty('--ig-size', info.size);
}
this.contentAppended.emit({ id: info.id, componentRef: info.componentRef });
info.settings.scrollStrategy.initialize(this._document, this, info.id);
info.settings.scrollStrategy.attach();
Expand Down Expand Up @@ -670,11 +675,6 @@ export class IgxOverlayService implements OnDestroy {
}

private updateSize(info: OverlayInfo) {
// set content div size
if (info.size) {
info.elementRef.nativeElement.parentElement.style.setProperty('--ig-size', info.size);
}

if (info.componentRef) {
// if we are positioning component this is first time it gets visible
// and we can finally get its size
Expand Down Expand Up @@ -984,7 +984,7 @@ export class IgxOverlayService implements OnDestroy {
}
}

private addComponentSize(info: OverlayInfo) {
private getComponentSize(info: OverlayInfo) {
if (info.elementRef?.nativeElement instanceof Element) {
const styles = this._document.defaultView.getComputedStyle(info.elementRef.nativeElement);
const componentSize = styles.getPropertyValue('--component-size');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
[itemHeight]="itemHeight" (click)="handleItemClick()" *igxFor="let item of data
| comboFiltering:filterValue:displayKey:filteringOptions:filterFunction
| comboGrouping:groupKey:valueKey:groupSortingDirection:compareCollator;
index as rowIndex; containerSize: itemsMaxHeight; scrollOrientation: 'vertical'; itemSize: itemHeight"
index as rowIndex; initialChunkSize: 10; containerSize: itemsMaxHeight || containerSize; itemSize: itemHeight || itemSize; scrollOrientation: 'vertical';"
[value]="item" [isHeader]="item?.isHeader" [index]="rowIndex">
<ng-container *ngIf="item?.isHeader">
<ng-container
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -588,8 +588,6 @@ describe('IgxSimpleCombo', () => {
expect(combo.displayKey).toEqual('field');
expect(combo.groupKey).toEqual('region');
expect(combo.width).toEqual('400px');
expect(combo.itemsMaxHeight).toEqual(320);
expect(combo.itemHeight).toEqual(32);
expect(combo.placeholder).toEqual('Location');
expect(combo.allowCustomValues).toEqual(false);
expect(combo.cssClass).toEqual(CSS_CLASS_COMBO);
Expand Down Expand Up @@ -671,9 +669,7 @@ describe('IgxSimpleCombo', () => {
const dropdownList = fixture.debugElement.query(By.css(`.${CSS_CLASS_CONTENT}`));

const verifyDropdownItemHeight = () => {
expect(combo.itemHeight).toEqual(itemHeight);
expect(dropdownItems[0].nativeElement.clientHeight).toEqual(itemHeight);
expect(combo.itemsMaxHeight).toEqual(itemMaxHeight);
expect(dropdownList.nativeElement.clientHeight).toEqual(itemMaxHeight);
};
verifyDropdownItemHeight();
Expand Down Expand Up @@ -2115,35 +2111,6 @@ describe('IgxSimpleCombo', () => {
}));
});

describe('Display density', () => {
beforeAll(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [
NoopAnimationsModule,
ReactiveFormsModule,
FormsModule,
IgxSimpleComboSampleComponent
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(IgxSimpleComboSampleComponent);
fixture.detectChanges();
combo = fixture.componentInstance.combo;
});
it('should scale items container depending on component size (itemHeight * 10)', () => {
combo.toggle();
fixture.detectChanges();
expect(combo.itemsMaxHeight).toEqual(320);
fixture.componentInstance.size = 'small';
fixture.detectChanges();
expect(combo.itemsMaxHeight).toEqual(280);
fixture.componentInstance.size = 'large';
fixture.detectChanges();
expect(combo.itemsMaxHeight).toEqual(400);
});
});

describe('Form control tests: ', () => {
describe('Template form tests: ', () => {
let inputGroupRequired: DebugElement;
Expand Down
Loading