@rx-angular/template
Version:
**Fully** Reactive Component Template Rendering in Angular. @rx-angular/template aims to be a reflection of Angular's built in renderings just reactive.
1,135 lines (1,124 loc) • 43.6 kB
TypeScript
import * as i0 from '@angular/core';
import { NgIterable, EmbeddedViewRef, ViewContainerRef, TrackByFunction, ElementRef, OnChanges, OnDestroy, SimpleChanges, OnInit, DoCheck, Signal, TemplateRef, InjectionToken, AfterViewInit, AfterContentInit } from '@angular/core';
import { RxDefaultListViewContext, RxListViewComputedContext } from '@rx-angular/cdk/template';
import * as rxjs from 'rxjs';
import { Observable, Subject } from 'rxjs';
import { RxStrategyNames } from '@rx-angular/cdk/render-strategies';
import * as _rx_angular_template_virtual_scrolling from '@rx-angular/template/virtual-scrolling';
interface ListRange {
start: number;
end: number;
}
/**
* @Directive RxVirtualScrollStrategy
*
* @description
* Abstract implementation for the actual implementations of the ScrollStrategies
* being consumed by `*rxVirtualFor` and `rx-virtual-scroll-viewport`.
*
* This is one of the core parts for the virtual scrolling implementation. It has
* to determine the `ListRange` being rendered to the DOM as well as managing
* the layouting task for the `*rxVirtualFor` directive.
*
* @docsCategory RxVirtualFor
* @docsPage RxVirtualFor
* @publicApi
*/
declare abstract class RxVirtualScrollStrategy<T, U extends NgIterable<T> = NgIterable<T>> {
/** Emits when the index of the first element visible in the viewport changes. */
/** @internal */
abstract scrolledIndex$: Observable<number>;
/** @internal */
abstract renderedRange$: Observable<ListRange>;
/** @internal */
abstract contentSize$: Observable<number>;
/** @internal */
get isStable(): Observable<boolean>;
/**
* @description
*
* Emits whenever an update to a single view was rendered
*/
readonly viewRenderCallback: Subject<{
view: EmbeddedViewRef<RxVirtualForViewContext<T, U>>;
item: T;
index: number;
}>;
/** @internal */
private nodeIndex?;
/** @internal */
protected getElement(view: EmbeddedViewRef<RxVirtualForViewContext<T, U>>): HTMLElement;
/**
* Attaches this scroll strategy to a viewport.
* @param viewport The viewport to attach this strategy to.
* @param viewRepeater The viewRepeater attached to the viewport.
*/
abstract attach(viewport: RxVirtualScrollViewport, viewRepeater: RxVirtualViewRepeater<any>): void;
/** Detaches this scroll strategy from the currently attached viewport. */
abstract detach(): void;
/**
* Scroll to the offset for the given index.
* @param index The index of the element to scroll to.
* @param behavior The ScrollBehavior to use when scrolling.
*/
abstract scrollToIndex(index: number, behavior?: ScrollBehavior): void;
static ɵfac: i0.ɵɵFactoryDeclaration<RxVirtualScrollStrategy<any, any>, never>;
static ɵdir: i0.ɵɵDirectiveDeclaration<RxVirtualScrollStrategy<any, any>, never, never, {}, {}, never, never, true, never>;
}
/** @internal */
declare abstract class RxVirtualScrollViewport {
abstract elementScrolled$: Observable<void>;
abstract containerRect$: Observable<{
height: number;
width: number;
}>;
abstract getScrollTop(): number;
abstract scrollTo(scrollTo: number, behavior?: ScrollBehavior): void;
abstract getScrollElement(): HTMLElement;
abstract measureOffset(): number;
static ɵfac: i0.ɵɵFactoryDeclaration<RxVirtualScrollViewport, never>;
static ɵdir: i0.ɵɵDirectiveDeclaration<RxVirtualScrollViewport, never, never, {}, {}, never, never, true, never>;
}
/** @internal */
declare abstract class RxVirtualViewRepeater<T, U extends NgIterable<T> = NgIterable<T>> {
abstract values$: Observable<U | null | undefined>;
abstract viewsRendered$: Observable<EmbeddedViewRef<RxVirtualForViewContext<T, U>>[]>;
abstract viewRendered$: Observable<{
view: EmbeddedViewRef<RxVirtualForViewContext<T, U>>;
index: number;
item: T;
}>;
abstract viewContainer: ViewContainerRef;
abstract renderingStart$: Observable<Set<number>>;
_trackBy: TrackByFunction<T> | null;
static ɵfac: i0.ɵɵFactoryDeclaration<RxVirtualViewRepeater<any, any>, never>;
static ɵdir: i0.ɵɵDirectiveDeclaration<RxVirtualViewRepeater<any, any>, never, never, {}, {}, never, never, true, never>;
}
/** @internal */
declare class RxVirtualForViewContext<T, U extends NgIterable<T> = NgIterable<T>, C extends {
count: number;
index: number;
} = {
count: number;
index: number;
}, K = keyof T> extends RxDefaultListViewContext<T, U, K> {
rxVirtualForOf: U;
constructor(item: T, rxVirtualForOf: U, customProps?: C);
}
declare abstract class RxVirtualScrollElement {
abstract elementScrolled$: Observable<void>;
abstract getElementRef(): ElementRef<HTMLElement>;
abstract measureOffset(): number;
static ɵfac: i0.ɵɵFactoryDeclaration<RxVirtualScrollElement, never>;
static ɵdir: i0.ɵɵDirectiveDeclaration<RxVirtualScrollElement, never, never, {}, {}, never, never, true, never>;
}
/**
* @Directive AutosizeVirtualScrollStrategy
*
* @description
*
* The `AutosizeVirtualScrollStrategy` provides a twitter-like virtual-scrolling
* experience. It is able to render and position items based on their individual
* size. It is comparable to \@angular/cdk/experimental `AutosizeVirtualScrollStrategy`, but
* with a high performant layouting technique and more features.
*
* On top of this the `AutosizeVirtualScrollStrategy` is leveraging the native
* `ResizeObserver` in order to detect size changes for each individual view
* rendered to the DOM and properly re-position accordingly.
*
* In order to provide top-notch runtime performance the `AutosizeVirtualScrollStrategy`
* builds up caches that prevent DOM interactions whenever possible. Once a view
* was visited, its properties will be stored instead of re-read from the DOM again as
* this can potentially lead to unwanted forced reflows.
*
* @docsCategory RxVirtualFor
* @docsPage RxVirtualFor
* @publicApi
*/
declare class AutoSizeVirtualScrollStrategy<T, U extends NgIterable<T> = NgIterable<T>> extends RxVirtualScrollStrategy<T, U> implements OnChanges, OnDestroy {
private readonly defaults?;
/**
* @description
* The amount of items to render upfront in scroll direction
*/
runwayItems: number;
/**
* @description
* The amount of items to render upfront in reverse scroll direction
*/
runwayItemsOpposite: number;
/**
* @description
* The default size of the items being rendered. The autosized strategy will assume
* this size for items it doesn't know yet. For the smoothest experience,
* you provide the mean size of all items being rendered - if possible of course.
*
* As soon as rxVirtualFor is able to also render actual tombstone items, this
* will be the size of a tombstone item being rendered before the actual item
* is inserted into its position.
*/
tombstoneSize: number;
/**
* @description
* The autosized strategy uses the native ResizeObserver in order to determine
* if an item changed in size to afterwards properly position the views.
* You can customize the config passed to the ResizeObserver as well as determine
* which result property to use when determining the views size.
*/
resizeObserverConfig?: {
options?: ResizeObserverOptions;
extractSize?: (entry: ResizeObserverEntry) => number;
};
/**
* @description
* When enabled, the autosized scroll strategy attaches a `ResizeObserver`
* to every view within the given renderedRange. If your views receive
* dimension changes that are not caused by list updates, this is a way to
* still track height changes. This also applies to resize events of the whole
* document.
*/
withResizeObserver: boolean;
/**
* @description
* When enabled, the scroll strategy stops removing views from the viewport,
* instead it only adds views. This setting can be changed on the fly. Views will be added in both directions
* according to the user interactions.
*/
appendOnly: boolean;
/**
* @description
* When enabled, the autosized scroll strategy removes css styles that
* prevent the scrollbar from being in sync with the input device.
* Use with caution, as this can lead to extremely weird scroll behavior
* on chromium based browsers when the rendered views differ
* in dimensions too much or change dimensions heavily.
*/
withSyncScrollbar: boolean;
/**
* @description
* If this flag is true, the virtual scroll strategy maintains the scrolled item when new data
* is prepended to the list. This is very useful when implementing a reversed infinite scroller, that prepends
* data instead of appending it
*/
keepScrolledIndexOnPrepend: boolean;
/** @internal */
private viewport;
/** @internal */
private viewRepeater;
/** @internal */
private readonly _contentSize$;
/** @internal */
readonly contentSize$: Observable<number>;
/** @internal */
private _contentSize;
/** @internal */
private set contentSize(value);
private get contentSize();
/** @internal */
private readonly _renderedRange$;
/** @internal */
readonly renderedRange$: Observable<ListRange>;
/** @internal */
private _renderedRange;
/** @internal */
private set renderedRange(value);
/** @internal */
private get renderedRange();
/** @internal */
private positionedRange;
/** @internal */
private readonly _scrolledIndex$;
/** @internal */
readonly scrolledIndex$: Observable<number>;
/**
* @internal
* The action used to kick off the scroll process
*/
private scrollToTrigger$;
/** @internal */
private _scrolledIndex;
/** @internal */
private get scrolledIndex();
/** @internal */
private set scrolledIndex(value);
/**
* is set, when scrollToIndex is called
* @internal
* */
private _scrollToIndex;
/** @internal */
private containerSize;
/** @internal */
private contentLength;
/** @internal */
private _virtualItems;
/** @internal */
private scrollTop;
/** @internal */
private scrollTopWithOutOffset;
/** @internal */
private scrollTopAfterOffset;
/** @internal */
private viewportOffset;
/** @internal */
private direction;
/** @internal */
private anchorScrollTop;
/** @internal */
private anchorItem;
/** @internal */
private lastScreenItem;
/** @internal */
private waitForScroll;
/** @internal */
private isStable$;
/** @internal */
private readonly detached$;
/** @internal */
private resizeObserver;
/** @internal */
private readonly recalculateRange$;
/** @internal */
private until$;
/** @internal */
private get extractSize();
/** @internal */
get isStable(): Observable<boolean>;
/** @internal */
ngOnChanges(changes: SimpleChanges): void;
/** @internal */
ngOnDestroy(): void;
/** @internal */
attach(viewport: RxVirtualScrollViewport, viewRepeater: RxVirtualViewRepeater<T, U>): void;
/** @internal */
detach(): void;
scrollToIndex(index: number, behavior?: ScrollBehavior): void;
private scrollTo;
/**
* starts the subscriptions that maintain the virtualItems array on changes
* to the underlying dataset
* @internal
*/
private maintainVirtualItems;
/**
* listen to triggers that should change the renderedRange
* @internal
*/
private calcRenderedRange;
/**
* position elements after they are created/updated/moved or their dimensions
* change from other sources
* @internal
*/
private positionElements;
/** listen to API initiated scroll triggers (e.g. initialScrollIndex) */
private listenToScrollTrigger;
/** @internal */
private adjustContentSize;
/** @internal */
private observeViewSize$;
/**
* @internal
* heavily inspired by
* https://github.com/GoogleChromeLabs/ui-element-samples/blob/gh-pages/infinite-scroller/scripts/infinite-scroll.js
*/
private calculateAnchoredItem;
/** @internal */
private positionUnchangedViews;
/**
* Adjust the scroll position when the anchorScrollTop differs from
* the actual scrollTop.
* Trigger a range recalculation if there is empty space
*
* @internal
*/
private maybeAdjustScrollPosition;
/** @internal */
private calcAnchorScrollTop;
/** @internal */
private calcInitialPosition;
/** @internal */
private getViewRef;
/** @internal */
private updateElementSize;
/** @internal */
private getItemSize;
/** @internal */
private getElementSize;
/** @internal */
private positionElement;
/** @internal */
private updateScrollElementClass;
static ɵfac: i0.ɵɵFactoryDeclaration<AutoSizeVirtualScrollStrategy<any, any>, never>;
static ɵdir: i0.ɵɵDirectiveDeclaration<AutoSizeVirtualScrollStrategy<any, any>, "rx-virtual-scroll-viewport[autosize]", never, { "runwayItems": { "alias": "runwayItems"; "required": false; }; "runwayItemsOpposite": { "alias": "runwayItemsOpposite"; "required": false; }; "tombstoneSize": { "alias": "tombstoneSize"; "required": false; }; "resizeObserverConfig": { "alias": "resizeObserverConfig"; "required": false; }; "withResizeObserver": { "alias": "withResizeObserver"; "required": false; }; "appendOnly": { "alias": "appendOnly"; "required": false; }; "withSyncScrollbar": { "alias": "withSyncScrollbar"; "required": false; }; "keepScrolledIndexOnPrepend": { "alias": "keepScrolledIndexOnPrepend"; "required": false; }; }, {}, never, never, true, never>;
static ngAcceptInputType_withResizeObserver: null | boolean | string | undefined;
static ngAcceptInputType_appendOnly: null | boolean | string | undefined;
static ngAcceptInputType_withSyncScrollbar: null | boolean | string | undefined;
static ngAcceptInputType_keepScrolledIndexOnPrepend: null | boolean | string | undefined;
}
/**
* @Directive DynamicSizeVirtualScrollStrategy
*
* @description
*
* The `DynamicSizeVirtualScrollStrategy` is very similar to the `AutosizeVirtualScrollStrategy`.
* It positions items based on a function determining its size.
*
* @docsCategory RxVirtualFor
* @docsPage RxVirtualFor
* @publicApi
*/
declare class DynamicSizeVirtualScrollStrategy<T, U extends NgIterable<T> = NgIterable<T>> extends RxVirtualScrollStrategy<T, U> implements OnChanges, OnDestroy {
private readonly defaults?;
/**
* @description
* The amount of items to render upfront in scroll direction
*/
runwayItems: number;
/**
* @description
* The amount of items to render upfront in reverse scroll direction
*/
runwayItemsOpposite: number;
/**
* @description
* When enabled, the scroll strategy stops removing views from the viewport,
* instead it only adds views. This setting can be changed on the fly. Views will be added in both directions
* according to the user interactions.
*/
appendOnly: boolean;
/**
* @description
* If this flag is true, the virtual scroll strategy maintains the scrolled item when new data
* is prepended to the list. This is very useful when implementing a reversed infinite scroller, that prepends
* data instead of appending it
*/
keepScrolledIndexOnPrepend: boolean;
/**
* @description
* Function returning the size of an item
*/
set itemSize(fn: (item: T) => number);
get itemSize(): (item: T) => number;
private _itemSizeFn;
/** @internal */
private waitForScroll;
/** @internal */
private isStable$;
/** @internal */
get isStable(): Observable<boolean>;
/** @internal */
private viewport;
/** @internal */
private viewRepeater;
/** @internal */
private readonly _contentSize$;
/** @internal */
readonly contentSize$: Observable<number>;
/** @internal */
private _contentSize;
/** @internal */
private set contentSize(value);
private get contentSize();
/** @internal */
private readonly _renderedRange$;
/** @internal */
readonly renderedRange$: Observable<ListRange>;
/** @internal */
private _renderedRange;
/** @internal */
private set renderedRange(value);
/** @internal */
private get renderedRange();
/** @internal */
private readonly _scrolledIndex$;
/** @internal */
readonly scrolledIndex$: Observable<number>;
private _scrolledIndex;
/** @internal */
private set scrolledIndex(value);
private get scrolledIndex();
/** @internal */
private get contentLength();
/** @internal */
private containerSize;
/** @internal */
private _virtualItems;
/** @internal */
private scrollTop;
/** @internal */
private scrollTopWithOutOffset;
/** @internal */
private scrollTopAfterOffset;
/** @internal */
private viewportOffset;
/** @internal */
private direction;
/** @internal */
private anchorScrollTop;
/** @internal */
private anchorItem;
/** @internal */
private lastScreenItem;
/** @internal */
private readonly detached$;
/** @internal */
private readonly recalculateRange$;
/** @internal */
private until$;
/** @internal */
ngOnChanges(changes: SimpleChanges): void;
/** @internal */
ngOnDestroy(): void;
/** @internal */
attach(viewport: RxVirtualScrollViewport, viewRepeater: RxVirtualViewRepeater<T, U>): void;
/** @internal */
detach(): void;
scrollToIndex(index: number, behavior?: ScrollBehavior): void;
private scrollTo;
/** @internal */
private maintainVirtualItems;
/** @internal */
private calcRenderedRange;
/** @internal */
private positionElements;
/**
* @internal
* heavily inspired by
* https://github.com/GoogleChromeLabs/ui-element-samples/blob/gh-pages/infinite-scroller/scripts/infinite-scroll.js
*/
private calculateAnchoredItem;
/** @internal */
private calcInitialPosition;
/** @internal */
private calcAnchorScrollTop;
/** @internal */
private getItemSize;
/** @internal */
private positionElement;
static ɵfac: i0.ɵɵFactoryDeclaration<DynamicSizeVirtualScrollStrategy<any, any>, never>;
static ɵdir: i0.ɵɵDirectiveDeclaration<DynamicSizeVirtualScrollStrategy<any, any>, "rx-virtual-scroll-viewport[dynamic]", never, { "runwayItems": { "alias": "runwayItems"; "required": false; }; "runwayItemsOpposite": { "alias": "runwayItemsOpposite"; "required": false; }; "appendOnly": { "alias": "appendOnly"; "required": false; }; "keepScrolledIndexOnPrepend": { "alias": "keepScrolledIndexOnPrepend"; "required": false; }; "itemSize": { "alias": "dynamic"; "required": false; }; }, {}, never, never, true, never>;
static ngAcceptInputType_appendOnly: null | boolean | string | undefined;
static ngAcceptInputType_keepScrolledIndexOnPrepend: null | boolean | string | undefined;
}
/**
* @Directive FixedSizeVirtualScrollStrategy
*
* @description
*
* The `FixedSizeVirtualScrollStrategy` provides a very performant way of rendering
* items of a given size. It is comparable to \@angular/cdk `FixedSizeVirtualScrollStrategy`, but
* with a high performant layouting technique.
*
* @docsCategory RxVirtualFor
* @docsPage RxVirtualFor
* @publicApi
*/
declare class FixedSizeVirtualScrollStrategy<T, U extends NgIterable<T> = NgIterable<T>> extends RxVirtualScrollStrategy<T, U> implements OnChanges, OnDestroy {
private readonly defaults?;
/**
* @description
* The size of the items in the virtually scrolled list
*/
set itemSize(itemSize: number);
get itemSize(): number;
private _itemSize;
/**
* @description
* When enabled, the scroll strategy stops removing views from the viewport,
* instead it only adds views. This setting can be changed on the fly. Views will be added in both directions
* according to the user interactions.
*/
appendOnly: boolean;
/**
* @description
* The amount of items to render upfront in scroll direction
*/
runwayItems: number;
/**
* @description
* The amount of items to render upfront in reverse scroll direction
*/
runwayItemsOpposite: number;
/**
* @description
* If this flag is true, the virtual scroll strategy maintains the scrolled item when new data
* is prepended to the list. This is very useful when implementing a reversed infinite scroller, that prepends
* data instead of appending it
*/
keepScrolledIndexOnPrepend: boolean;
/** @internal */
private readonly runwayStateChanged$;
private viewport;
private viewRepeater;
private readonly _scrolledIndex$;
readonly scrolledIndex$: rxjs.Observable<number>;
private _scrolledIndex;
private set scrolledIndex(value);
private get scrolledIndex();
private readonly _contentSize$;
readonly contentSize$: rxjs.Observable<number>;
private _contentSize;
private set contentSize(value);
private readonly _renderedRange$;
renderedRange$: rxjs.Observable<ListRange>;
private _renderedRange;
private set renderedRange(value);
private get renderedRange();
private scrollTop;
/** @internal */
private scrollTopWithOutOffset;
/** @internal */
private scrollTopAfterOffset;
/** @internal */
private viewportOffset;
/** @internal */
private containerSize;
private direction;
private readonly detached$;
/** @internal */
ngOnChanges(changes: SimpleChanges): void;
ngOnDestroy(): void;
attach(viewport: RxVirtualScrollViewport, viewRepeater: RxVirtualViewRepeater<T, U>): void;
detach(): void;
private positionElements;
private calcRenderedRange;
scrollToIndex(index: number, behavior?: ScrollBehavior): void;
private untilDetached$;
private _setViewPosition;
static ɵfac: i0.ɵɵFactoryDeclaration<FixedSizeVirtualScrollStrategy<any, any>, never>;
static ɵdir: i0.ɵɵDirectiveDeclaration<FixedSizeVirtualScrollStrategy<any, any>, "rx-virtual-scroll-viewport[itemSize]", never, { "itemSize": { "alias": "itemSize"; "required": false; }; "appendOnly": { "alias": "appendOnly"; "required": false; }; "runwayItems": { "alias": "runwayItems"; "required": false; }; "runwayItemsOpposite": { "alias": "runwayItemsOpposite"; "required": false; }; "keepScrolledIndexOnPrepend": { "alias": "keepScrolledIndexOnPrepend"; "required": false; }; }, {}, never, never, true, never>;
static ngAcceptInputType_appendOnly: null | boolean | string | undefined;
static ngAcceptInputType_keepScrolledIndexOnPrepend: null | boolean | string | undefined;
}
/**
* @Directive RxVirtualFor
*
* @description
*
* The `*rxVirtualFor` structural directive provides a convenient and performant
* way for rendering huge lists of items. It brings all the benefits `rxFor` does,
* and implements virtual rendering.
*
* Instead of rendering every item provided, rxVirtualFor only renders what is
* currently visible to the user, thus providing excellent runtime performance
* for huge sets of data.
*
* The technique to render items is comparable to the on used by twitter and
* explained in very much detail by @DasSurma in his blog post about the [complexities
* of infinite scrollers](https://developer.chrome.com/blog/infinite-scroller/).
*
* "Each recycling of a DOM element would normally relayout the entire runway which
* would bring us well below our target of 60 frames per second.
* To avoid this, we are taking the burden of layout onto ourselves and use
* absolutely positioned elements with transforms." (@DasSurma)
*
* ## API
* The API is a combination of \@rx-angular/template/for &
* \@angular/cdk `*cdkVirtualFor`.
* * trackBy: `(index: number, item: T) => any` | `keyof T`
* * strategy: `string` | `Observable<string>`
* * parent: `boolean`;
* * renderCallback: `Subject<T[]>`
* * viewCache: `number`
* * (Injected) scrollStrategy: `RxVirtualScrollStrategy<T, U>`
* * provides itself as RxVirtualViewRepeater for RxVirtualViewPortComponent to operate
*
* ## Features
* * Push based architecture
* * Comprehensive set of context variables
* * Opt-out of `NgZone` with `patchZone`
* * Notify when rendering of child templates is finished (`renderCallback`)
* * Super efficient layouting with css transformations
* * Define a viewCache in order to re-use views instead of re-creating them
* * Configurable RxVirtualScrollStrategy<T, U> providing the core logic to calculate the viewRange and position DOM
* Nodes
*
* ### Context Variables
*
* The following context variables are available for each template:
*
* - $implicit: `T` // the default variable accessed by `let val`
* - item$: `Observable<T>` // the same value as $implicit, but as `Observable`
* - index: `number` // current index of the item
* - count: `number` // count of all items in the list
* - first: `boolean` // true if the item is the first in the list
* - last: `boolean` // true if the item is the last in the list
* - even: `boolean` // true if the item has on even index (index % 2 === 0)
* - odd: `boolean` // the opposite of even
* - index$: `Observable<number>` // index as `Observable`
* - count$: `Observable<number>` // count as `Observable`
* - first$: `Observable<boolean>` // first as `Observable`
* - last$: `Observable<boolean>` // last as `Observable`
* - even$: `Observable<boolean>` // even as `Observable`
* - odd$: `Observable<boolean>` // odd as `Observable`
* - select: `(keys: (keyof T)[], distinctByMap) => Observable<Partial<T>>`
* // returns a selection function which
* // accepts an array of properties to pluck out of every list item. The function returns the selected properties of
* // the current list item as distinct `Observable` key-value-pair. See the example below:
*
* This example showcases the `select` view-context function used for deeply nested lists.
*
* ```html
* <rx-virtual-scroll-viewport>
* <div
* autosized
* *rxVirtualFor="let hero of heroes$; trackBy: trackItem; let select = select;">
* <div>
* <strong>{{ hero.name }}</strong></br>
* Defeated enemies:
* </div>
* <span *rxFor="let enemy of select(['defeatedEnemies']); trackBy: trackEnemy;">
* {{ enemy.name }}
* </span>
* </div>
* </rx-virtual-scroll-viewport>
* ```
*
* ### Using the context variables
*
* ```html
* <rx-virtual-scroll-viewport>
* <div
* *rxVirtualFor="
* let item of observableItems$;
* let count = count;
* let index = index;
* let first = first;
* let last = last;
* let even = even;
* let odd = odd;
* trackBy: trackItem;
* "
* >
* <div>{{ count }}</div>
* <div>{{ index }}</div>
* <div>{{ item }}</div>
* <div>{{ first }}</div>
* <div>{{ last }}</div>
* <div>{{ even }}</div>
* <div>{{ odd }}</div>
* </div>
* </rx-virtual-scroll-viewport>
* ```
*
* @docsCategory RxVirtualFor
* @docsPage RxVirtualFor
* @publicApi
*/
declare class RxVirtualFor<T, U extends NgIterable<T> = NgIterable<T>> implements RxVirtualViewRepeater<T>, OnInit, DoCheck, OnDestroy {
private readonly templateRef;
private readonly scrollStrategy;
private readonly iterableDiffers;
private readonly cdRef;
private readonly ngZone;
/** @internal */
private injector;
readonly viewContainer: ViewContainerRef;
private readonly strategyProvider;
private readonly errorHandler;
private readonly defaults?;
/** @internal */
private _differ?;
/** @internal */
private partiallyFinished;
/** @internal */
private staticValue?;
/** @internal */
private renderStatic;
/**
* @description
* The iterable input
*
* @example
* <rx-virtual-scroll-viewport>
* <app-hero *rxVirtualFor="heroes$; let hero"
* [hero]="hero"></app-hero>
* </rx-virtual-scroll-viewport>
*
* @param potentialSignalOrObservable
*/
set rxVirtualForOf(potentialSignalOrObservable: Observable<(U & NgIterable<T>) | undefined | null> | Signal<(U & NgIterable<T>) | undefined | null> | (U & NgIterable<T>) | null | undefined);
/**
* @internal
* A reference to the template that is created for each item in the iterable.
* @see [template reference variable](guide/template-reference-variables)
* (inspired by @angular/common `ng_for_of.ts`)
*/
private _template?;
set rxVirtualForTemplate(value: TemplateRef<RxVirtualForViewContext<T, U>>);
/** @internal */
private strategyHandler;
/**
* @description
* The rendering strategy to be used to render updates to the DOM.
* Use it to dynamically manage your rendering strategy. You can switch the strategy
* imperatively (with a string) or by binding an Observable.
* The default strategy is `'normal'` if not configured otherwise.
*
* @example
* \@Component({
* selector: 'app-root',
* template: `
* <rx-virtual-scroll-viewport>
* <app-hero
* autosized
* *rxVirtualFor="let hero of heroes$; strategy: strategy"
* [hero]="hero"></app-hero>
* </rx-virtual-scroll-viewport>
* `
* })
* export class AppComponent {
* strategy = 'low';
* }
*
* // OR
*
* \@Component({
* selector: 'app-root',
* template: `
* <rx-virtual-scroll-viewport>
* <app-hero
* autosized
* *rxVirtualFor="let hero of heroes$; strategy: strategy$"
* [hero]="hero"></app-hero>
* </rx-virtual-scroll-viewport>
* `
* })
* export class AppComponent {
* strategy$ = new BehaviorSubject('immediate');
* }
*
* @param strategyName
* @see {@link strategies}
*/
set strategy(strategyName: RxStrategyNames<string> | Observable<RxStrategyNames<string>>);
/**
* @description
* Controls the amount if views held in cache for later re-use when a user is
* scrolling the list. If this is set to 0, `rxVirtualFor` won't cache any view,
* thus destroying & re-creating very often on scroll events.
*/
templateCacheSize: number;
/**
* @description
* If `parent` is set to `true` (default to `false`), `*rxVirtualFor` will
* automatically run change-detection for its parent component when its scheduled
* tasks are done in order to update any pending `@ContentChild` or `@ViewChild`
* relation to be updated according to the updated ViewContainer.
*
* @example
* \@Component({
* selector: 'app-root',
* template: `
* <rx-virtual-scroll-viewport>
* <app-list-item
* *rxVirtualFor="
* let item of items$;
* trackBy: trackItem;
* parent: true;
* "
* [item]="item"
* autosized
* ></app-list-item>
* </rx-virtual-scroll-viewport>
* `
* })
* export class AppComponent {
* // those queries won't be in sync with what `rxVirtualFor` is rendering
* // when parent is set to false.
* \@ViewChildren(AppListItem) listItems: QueryList<AppListItem>;
*
* items$ = itemService.getItems();
* }
*
* @param renderParent
*
* @deprecated this flag will be dropped soon, as it is no longer required when using signal based view & content queries
*/
renderParent: boolean;
/**
* @description
* A flag to control whether `*rxVirtualFor` rendering happens within
* `NgZone` or not. The default value is set to `true` if not configured otherwise.
* If `patchZone` is set to `false` `*rxVirtualFor` will operate completely outside of `NgZone`.
*
* @example
* \@Component({
* selector: 'app-root',
* template: `
* <rx-virtual-scroll-viewport>
* <app-list-item
* *rxVirtualFor="
* let item of items$;
* trackBy: trackItem;
* patchZone: false;
* "
* [item]="item"
* autosized
* ></app-list-item>
* </rx-virtual-scroll-viewport>
* `
* })
* export class AppComponent {
* items$ = itemService.getItems();
* }
*
* @param patchZone
*/
patchZone: boolean;
/**
* @description
* A function or key that defines how to track changes for items in the provided
* iterable data.
*
* When items are added, moved, or removed in the iterable,
* the directive must re-render the appropriate DOM nodes.
* To minimize operations on the DOM, only nodes that have changed
* are re-rendered.
*
* By default, `rxVirtualFor` assumes that the object instance identifies
* the node in the iterable (equality check `===`).
* When a function or key is supplied, `rxVirtualFor` uses the result to identify the item node.
*
* @example
* \@Component({
* selector: 'app-root',
* template: `
* <rx-virtual-scroll-viewport>
* <app-list-item
* *rxVirtualFor="
* let item of items$;
* trackBy: 'id';
* "
* autosized
* [item]="item"
* >
* </app-list-item>
* </rx-virtual-scroll-viewport>
* `
* })
* export class AppComponent {
* items$ = itemService.getItems();
* }
*
* // OR
*
* \@Component({
* selector: 'app-root',
* template: `
* <rx-virtual-scroll-viewport>
* <app-list-item
* *rxVirtualFor="
* let item of items$;
* trackBy: trackItem;
* "
* autosized
* [item]="item"
* >
* </app-list-item>
* </rx-virtual-scroll-viewport>
* `
* })
* export class AppComponent {
* items$ = itemService.getItems();
* trackItem = (idx, item) => item.id;
* }
*
* @param trackByFnOrKey
*/
set trackBy(trackByFnOrKey: keyof T | TrackByFunction<T>);
/**
* @description
* A `Subject` which emits whenever `*rxVirtualFor` finished rendering a
* set of changes to the view.
* This enables developers to perform actions exactly at the timing when the
* updates passed are rendered to the DOM.
* The `renderCallback` is useful in situations where you rely on specific DOM
* properties like the `height` of a table after all items got rendered.
* It is also possible to use the renderCallback in order to determine if a
* view should be visible or not. This way developers can hide a list as
* long as it has not finished rendering.
*
* The result of the `renderCallback` will contain the currently rendered set
* of items in the iterable.
*
* @example
* \@Component({
* selector: 'app-root',
* template: `
* <rx-virtual-scroll-viewport>
* <app-list-item
* *rxVirtualFor="
* let item of items$;
* trackBy: trackItem;
* renderCallback: itemsRendered;
* "
* autosized
* [item]="item"
* >
* </app-list-item>
* </rx-virtual-scroll-viewport>
* `
* })
* export class AppComponent {
* items$: Observable<Item[]> = itemService.getItems();
* trackItem = (idx, item) => item.id;
* // this emits whenever rxVirtualFor finished rendering changes
* itemsRendered = new Subject<Item[]>();
* }
*
* @param renderCallback
*/
set renderCallback(renderCallback: Subject<U>);
/** @internal */
readonly viewsRendered$: Subject<EmbeddedViewRef<RxVirtualForViewContext<T, U, RxListViewComputedContext, keyof T>>[]>;
/** @internal */
readonly viewRendered$: Subject<{
view: EmbeddedViewRef<RxVirtualForViewContext<T, U>>;
index: number;
item: T;
}>;
/** @internal */
readonly renderingStart$: Subject<Set<number>>;
/** @internal */
private get template();
/** @internal */
private observables$;
/** @internal */
private _renderCallback?;
/** @internal */
readonly values$: Observable<NgIterable<T>>;
/** @internal */
private values?;
/** @internal */
private templateManager;
/** @internal */
private _destroy$;
/** @internal */
_trackBy: TrackByFunction<T> | null;
/** @internal */
static ngTemplateContextGuard<T, U extends NgIterable<T> = NgIterable<T>, K = keyof T>(dir: RxVirtualFor<T, U>, ctx: any): ctx is RxVirtualForViewContext<T, U, RxListViewComputedContext, K>;
constructor(templateRef: TemplateRef<RxVirtualForViewContext<T, U>>);
/** @internal */
ngOnInit(): void;
/** @internal */
ngDoCheck(): void;
/** @internal */
ngOnDestroy(): void;
private render;
private handleError;
private getDiffer;
/** @internal */
private createViewContext;
/** @internal */
private updateViewContext;
static ɵfac: i0.ɵɵFactoryDeclaration<RxVirtualFor<any, any>, never>;
static ɵdir: i0.ɵɵDirectiveDeclaration<RxVirtualFor<any, any>, "[rxVirtualFor][rxVirtualForOf]", never, { "rxVirtualForOf": { "alias": "rxVirtualForOf"; "required": false; }; "rxVirtualForTemplate": { "alias": "rxVirtualForTemplate"; "required": false; }; "strategy": { "alias": "rxVirtualForStrategy"; "required": false; }; "templateCacheSize": { "alias": "rxVirtualForTemplateCacheSize"; "required": false; }; "renderParent": { "alias": "rxVirtualForParent"; "required": false; }; "patchZone": { "alias": "rxVirtualForPatchZone"; "required": false; }; "trackBy": { "alias": "rxVirtualForTrackBy"; "required": false; }; "renderCallback": { "alias": "rxVirtualForRenderCallback"; "required": false; }; }, {}, never, never, true, never>;
}
interface RxVirtualScrollDefaultOptions {
templateCacheSize?: number;
runwayItems?: number;
runwayItemsOpposite?: number;
itemSize?: number;
}
/** Injection token to be used to override the default options. */
declare const RX_VIRTUAL_SCROLL_DEFAULT_OPTIONS: InjectionToken<RxVirtualScrollDefaultOptions>;
/** @internal */
declare function RX_VIRTUAL_SCROLL_DEFAULT_OPTIONS_FACTORY(): RxVirtualScrollDefaultOptions;
declare class RxVirtualScrollElementDirective implements RxVirtualScrollElement {
private readonly elementRef;
readonly elementScrolled$: rxjs.Observable<void>;
getElementRef(): ElementRef<HTMLElement>;
measureOffset(): number;
static ɵfac: i0.ɵɵFactoryDeclaration<RxVirtualScrollElementDirective, never>;
static ɵdir: i0.ɵɵDirectiveDeclaration<RxVirtualScrollElementDirective, "[rxVirtualScrollElement]", never, {}, {}, never, never, true, never>;
}
/**
* @Component RxVirtualScrollViewport
*
* @description
* Container component comparable to CdkVirtualScrollViewport acting as viewport
* for `*rxVirtualFor` to operate on.
*
* Its main purpose is to implement the `RxVirtualScrollViewport` interface
* as well as maintaining the scroll runways' height in order to give
* the provided `RxVirtualScrollStrategy` room to position items.
*
* Furthermore, it will gather and forward all events to the consumer of `rxVirtualFor`.
*
* @docsCategory RxVirtualFor
* @docsPage RxVirtualFor
* @publicApi
*/
declare class RxVirtualScrollViewportComponent implements RxVirtualScrollViewport, AfterViewInit, AfterContentInit, OnDestroy {
private elementRef;
private scrollStrategy;
protected scrollElement: RxVirtualScrollElement;
/**
* @description
*
* Sets the first view to be visible to the user.
* The viewport waits for the data to arrive and scrolls to the given index immediately.
*
* */
initialScrollIndex: number;
/** @internal */
private scrollSentinel;
/** @internal */
private runway;
/** @internal */
viewRepeater: RxVirtualViewRepeater<unknown>;
readonly elementScrolled$: rxjs.Observable<void>;
/** @internal */
private _containerRect$;
readonly containerRect$: rxjs.Observable<{
width: number;
height: number;
}>;
/**
* @description
*
* The range to be rendered by `*rxVirtualFor`. This value is determined by the
* provided `RxVirtualScrollStrategy`. It gives the user information about the
* range of items being actually rendered to the DOM.
* Note this value updates before the `renderCallback` kicks in, thus it is only
* in sync with the DOM when the next `renderCallback` emitted an event.
*/
readonly viewRange: rxjs.Observable<_rx_angular_template_virtual_scrolling.ListRange>;
/**
* @description
*
* The index of the currently scrolled item. The scrolled item is the topmost
* item actually being visible to the user.
*/
readonly scrolledIndexChange: rxjs.Observable<number>;
/** @internal */
private readonly destroy$;
/** @internal */
constructor();
ngAfterViewInit(): void;
/** @internal */
ngAfterContentInit(): void;
/** @internal */
ngOnDestroy(): void;
getScrollElement(): HTMLElement;
getScrollTop(): number;
scrollTo(position: number, behavior?: ScrollBehavior): void;
scrollToIndex(index: number, behavior?: ScrollBehavior): void;
measureOffset(): number;
protected updateContentSize(size: number): void;
static ɵfac: i0.ɵɵFactoryDeclaration<RxVirtualScrollViewportComponent, never>;
static ɵcmp: i0.ɵɵComponentDeclaration<RxVirtualScrollViewportComponent, "rx-virtual-scroll-viewport", never, { "initialScrollIndex": { "alias": "initialScrollIndex"; "required": false; }; }, { "viewRange": "viewRange"; "scrolledIndexChange": "scrolledIndexChange"; }, ["viewRepeater"], ["*"], true, never>;
}
declare class RxVirtualScrollWindowDirective implements RxVirtualScrollElement {
private readonly document;
private readonly elementRef;
readonly elementScrolled$: rxjs.Observable<void>;
getElementRef(): ElementRef<HTMLElement>;
measureOffset(): number;
static ɵfac: i0.ɵɵFactoryDeclaration<RxVirtualScrollWindowDirective, never>;
static ɵdir: i0.ɵɵDirectiveDeclaration<RxVirtualScrollWindowDirective, "rx-virtual-scroll-viewport[scrollWindow]", never, {}, {}, never, never, true, never>;
}
export { AutoSizeVirtualScrollStrategy, DynamicSizeVirtualScrollStrategy, FixedSizeVirtualScrollStrategy, RX_VIRTUAL_SCROLL_DEFAULT_OPTIONS, RX_VIRTUAL_SCROLL_DEFAULT_OPTIONS_FACTORY, RxVirtualFor, RxVirtualForViewContext, RxVirtualScrollElement, RxVirtualScrollElementDirective, RxVirtualScrollStrategy, RxVirtualScrollViewport, RxVirtualScrollViewportComponent, RxVirtualScrollWindowDirective, RxVirtualViewRepeater };
export type { ListRange, RxVirtualScrollDefaultOptions };