Skip to content
Open
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
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,18 @@ All notable changes for each version of this project will be documented in this

## 22.2.0

### General

- The Excel style filtering search list, `IgxComboComponent` and `IgxSimpleComboComponent` are now virtualized by `IgxVirtualScrollComponent` instead of the `igxFor` directive. A row is measured in the DOM once it renders and the measured size replaces the estimate it started from; rows that have not rendered keep that estimate.
- The list markup changed accordingly: `igx-display-container` and the `igx-vhelper--vertical` scrollbar are replaced by the `igx-virtual-scroll` host and its `igx-vs__item` row wrappers. Applications and tests that reach into those elements directly need updating.
- `IgxComboComponent.virtualScrollContainer` and `IgxSimpleComboComponent.virtualScrollContainer` are marked `@hidden @internal`; their concrete type follows the engine the combo uses.
- `IgxDropDownComponent` accepts a content-projected `igx-virtual-scroll` in addition to `*igxFor`, which keeps working as documented. Selection and navigation behave the same either way.

### New Features

- `IgxVirtualScrollComponent`
- Added `initialViewportSize`, the viewport size to render the first window against. A list that is hidden until the change detection pass that reveals it has no size to measure in that pass and would render nothing; this gives that first render a size to work from, and the host's own size takes over once it has been laid out.
- Added `dataWindow`, taking a loaded page of a larger collection as `{ items, startIndex, totalCount }`. The list is as long as `totalCount`, so the scrollbar spans the whole collection while only the page is in memory, and indices the page does not cover render nothing until a page that covers them arrives. `data` is unchanged and is used whenever `dataWindow` is not set.
Comment on lines +16 to +18
- `IgxChipComponent`
- Added the `outlined` property to the component. When set to `true`, the Chip will have an outlined style.

Expand All @@ -25,6 +35,13 @@ All notable changes for each version of this project will be documented in this

### Bug Fixes

- **Accessibility**
- Removed the nested list role from the internal virtual-scroll containers in Combo, Simple Combo and Excel-style filtering, preserving their existing listboxes and options.
- `IgxDropDownComponent`
- Navigation and item lookup now use the same normalized `dataWindow` indices and total count as the projected virtual scroll, including fractional or non-finite metadata and pages extending past the declared total.
- `IgxComboComponent`, `IgxSimpleComboComponent`
- Fixed remote pages changing position before their replacements arrive and redundant requests for an already loaded initial range. Changes to a positive `totalItemCount` refresh the list without rebinding data; a reduced total excludes out-of-range records before filtering and grouping.
- Reduced selection-resolution work during change detection. Each combo resolves its selection once per check and validates cached primitive-key matches before reusing them. Missing or invalid matches share one fallback scan; object keys retain deep-equality matching. In-place changes that create an earlier duplicate of a cached key are not detected without rebinding data.
- `IgxCheckboxComponent`
- Fixed the tick-mark icon rendering with the Indigo shape (rounded rect + custom path) inside CSS-scoped subtrees that use a different design system than the application's global theme, e.g. a `material`-themed widget nested inside an `indigo`-themed app. Both tick-mark variants are now always rendered and toggled purely via CSS (`@container style(--ig-theme: indigo)`), removing the dependency on JS-side theme detection that could go stale in nested/multi-theme scenarios (#15021).
- **Ripple**
Expand Down
19 changes: 19 additions & 0 deletions projects/igniteui-angular/combo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ public dataLoading(evt): void {
What the combo exposes is a `virtualizationState` property that gives state of the combo - first index and the number of items that needs to be loaded.
The service, should inform the combo for the total items that are on the server - using the `totalItemCount` property.

The first rendered range does not emit `dataPreLoad` when the initial page already covers it.
Later range changes still emit the event, so the consumer can cancel a superseded request.
Capture the requested range when starting a fetch and cancel its subscription before replacing
it; assigning `data` does not identify which request produced the page.

Changing a positive `totalItemCount` refreshes the list without rebinding `data`. If the total
shrinks, loaded records beyond it are excluded while the valid prefix keeps its position.
This limit is applied before filtering and grouping; group headers are not remote records.


## Features

Expand Down Expand Up @@ -86,6 +95,16 @@ export class MyCombo {
}
```

With primitive value keys, resolving the selection reuses previously found records
after verifying their index, identity and key. Missing or invalid matches share one
fallback scan. Changing the data array, its length or `valueKey` clears the lookup;
object keys retain deep-equality matching. A selected key whose record is not loaded
is represented by `{ [valueKey]: key }` and is checked again on the next resolution.

The hit validation does not detect a different record becoming an earlier duplicate
of an already cached key without rebinding the data. This remains a known limitation
of the lookup, not a guarantee of compatibility with every in-place mutation.

### Selection Events

The `igx-combo` exposes both `selectionChanging` and `selectionChanged`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,7 @@ export class IgxComboDropDownComponent extends IgxDropDownComponent implements I

/** @hidden @internal */
public override get scrollContainer(): HTMLElement {
// TODO: Update, use public API if possible:
return this.virtDir.dc.location.nativeElement;
}

protected get isScrolledToLast(): boolean {
const scrollTop = this.virtDir.scrollPosition;
const scrollHeight = this.virtDir.getScroll()!.scrollHeight;
return Math.floor(scrollTop + this.virtDir.igxForContainerSize) === scrollHeight;
return this.virtualization!.scrollElement;
}

protected get lastVisibleIndex(): number {
Expand Down Expand Up @@ -137,15 +130,19 @@ export class IgxComboDropDownComponent extends IgxDropDownComponent implements I
* @hidden
*/
public override navigateFirst() {
this.navigateItem(this.virtDir.igxForOf!.findIndex(e => !e?.isHeader));
// The first selectable entry can only be looked for in what is loaded. A page that
// starts further in does not hold it, so the collection's own start is the target.
this.navigateItem(this.virtualization?.startIndex === 0
? this.virtualization.findIndex(e => !e?.isHeader)
: 0);
this.combo.setActiveDescendant();
}

/**
* @hidden
*/
public override navigatePrev() {
if (this._focusedItem && this._focusedItem.index === 0 && this.virtDir.state.startIndex === 0) {
if (this._focusedItem && this._focusedItem.index === 0) {
this.combo.focusSearchInput(false);
this.focusedItem = null;
} else {
Expand All @@ -159,7 +156,7 @@ export class IgxComboDropDownComponent extends IgxDropDownComponent implements I
* @hidden
*/
public override navigateNext() {
const lastIndex = this.combo.totalItemCount ? this.combo.totalItemCount - 1 : this.virtDir.igxForOf!.length - 1;
const lastIndex = (this.virtualization?.length ?? 0) - 1;
if (this._focusedItem && this._focusedItem.index === lastIndex) {
this.focusAddItemButton();
} else {
Expand All @@ -185,7 +182,7 @@ export class IgxComboDropDownComponent extends IgxDropDownComponent implements I
* @hidden @internal
*/
public override updateScrollPosition() {
this.virtDir.getScroll()!.scrollTop = this._scrollPosition;
this.virtualization!.scrollPosition = this._scrollPosition;
}

/**
Expand All @@ -208,14 +205,15 @@ export class IgxComboDropDownComponent extends IgxDropDownComponent implements I
}

public override ngAfterViewInit() {
this.virtDir.getScroll()!.addEventListener('scroll', this.scrollHandler);
super.ngAfterViewInit();
this.scrollContainer.addEventListener('scroll', this.scrollHandler);
}

/**
* @hidden @internal
*/
public override ngOnDestroy(): void {
this.virtDir.getScroll()!.removeEventListener('scroll', this.scrollHandler);
this.virtualization?.scrollElement.removeEventListener('scroll', this.scrollHandler);
super.ngOnDestroy();
}

Expand Down
Loading