UNPKG

@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.

334 lines (333 loc) 12.3 kB
import { DoCheck, EmbeddedViewRef, NgIterable, OnDestroy, OnInit, Signal, TemplateRef, TrackByFunction } from '@angular/core'; import { RxStrategyNames } from '@rx-angular/cdk/render-strategies'; import { RxListViewComputedContext } from '@rx-angular/cdk/template'; import { Observable, Subject } from 'rxjs'; import { RxForViewContext } from './for-view-context'; import * as i0 from "@angular/core"; /** * @Directive RxFor * * @description * * The most common way to render lists in angular is by using the `*ngFor` structural directive. `*ngFor` is able * to take an arbitrary list of data and repeat a defined template per item of the list. However, it can * only do it synchronously. * * Compared to the `NgFor`, `RxFor` treats each child template as single renderable unit. * The change detection of the child templates get prioritized, scheduled and executed by * leveraging `RenderStrategies` under the hood. * This technique enables non-blocking rendering of lists and can be referred to as `concurrent mode`. * * Read more about this in the [strategies * section](https://www.rx-angular.io/docs/template/rx-for-directive#rxfor-with-concurrent-strategies). * * Furthermore, `RxFor` provides hooks to react to rendered items in form of a `renderCallback: Subject`. * * Together with the `RxRenderStrategies`, this makes the rendering behavior extremely versatile * and transparent for the developer. * Each instance of `RxFor` can be configured to render with different settings. * * Read more in the [official docs](https://www.rx-angular.io/docs/template/rx-for-directive) * * @docsCategory RxFor * @docsPage RxFor * @publicApi */ export declare class RxFor<T, U extends NgIterable<T> = NgIterable<T>> implements OnInit, DoCheck, OnDestroy { private readonly templateRef; /** @internal */ private cdRef; /** @internal */ private ngZone; /** @internal */ private injector; /** @internal */ private viewContainerRef; /** @internal */ private strategyProvider; /** @internal */ private errorHandler; /** @internal */ private staticValue?; /** @internal */ private renderStatic; /** * @description * The iterable input * * @example * <ng-container *rxFor="heroes$; let hero"> * <app-hero [hero]="hero"></app-hero> * </ng-container> * * @param { Observable<(U & NgIterable<T>) | undefined | null> * | Signal<(U & NgIterable<T>) | undefined | null> * | (U & NgIterable<T>) * | null * | undefined } potentialSignalOrObservable */ set rxForOf(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 rxForTemplate(value: TemplateRef<RxForViewContext<T, U>>); /** * @description * * You can change the used `RenderStrategy` by using the `strategy` input of the `*rxFor`. It accepts * an `Observable<RxStrategyNames>` or * [`RxStrategyNames`](https://github.com/rx-angular/rx-angular/blob/b0630f69017cc1871d093e976006066d5f2005b9/libs/cdk/render-strategies/src/lib/model.ts#L52). * * The default value for strategy is * [`normal`](https://www.rx-angular.io/docs/template/cdk/render-strategies/strategies/concurrent-strategies). * * Read more about this in the * [official docs](https://www.rx-angular.io/docs/template/rx-for-directive#use-render-strategies-strategy). * * @example * * \@Component({ * selector: 'app-root', * template: ` * <ng-container *rxFor="let hero of heroes$; strategy: strategy"> * <app-hero [hero]="hero"></app-hero> * </ng-container> * * <ng-container *rxFor="let hero of heroes$; strategy: strategy$"> * <app-hero [hero]="hero"></app-hero> * </ng-container> * ` * }) * export class AppComponent { * strategy = 'low'; * strategy$ = of('immediate'); * } * * @param {string | Observable<string> | undefined} strategyName * @see {@link strategies} */ set rxForStrategy(strategyName: RxStrategyNames | Observable<RxStrategyNames> | undefined); /** * @description * * When local rendering strategies are used, we need to treat view and content queries in a * special way. * To make `*rxFor` in such situations, a certain mechanism is implemented to * execute change detection on the parent (`parent`). * * This is required if your components state is dependent on its view or content children: * * - `@ViewChild` * - `@ViewChildren` * - `@ContentChild` * - `@ContentChildren` * * Read more about this in the * [official * docs](https://www.rx-angular.io/docs/template/rx-for-directive#local-strategies-and-view-content-queries-parent). * * @example * \@Component({ * selector: 'app-root', * template: ` * <app-list-component> * <app-list-item * *rxFor=" * let item of items$; * trackBy: trackItem; * parent: true; * " * > * <div>{{ item.name }}</div> * </app-list-item> * </app-list-component> * ` * }) * export class AppComponent { * items$ = itemService.getItems(); * } * * @param {boolean} 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 *rxFor templates are created within `NgZone` or not. * The default value is `true, `*rxFor` will create it's `EmbeddedViews` inside `NgZone`. * * Event listeners normally trigger zone. Especially high frequently events cause performance issues. * * Read more about this in the * [official * docs](https://www.rx-angular.io/docs/template/rx-for-directive#working-with-event-listeners-patchzone). * * @example * \@Component({ * selector: 'app-root', * template: ` * <app-list-component> * <app-list-item * *rxFor=" * let item of items$; * trackBy: trackItem; * patchZone: false; * " * > * <div>{{ item.name }}</div> * </app-list-item> * </app-list-component> * ` * }) * export class AppComponent { * items$ = itemService.getItems(); * } * * @param {boolean} patchZone */ patchZone: boolean; private defaultTrackBy; /** * @description * A function or key that defines how to track changes for items in the iterable. * * When items are added, moved, or removed in the iterable, * the directive must re-render the appropriate DOM nodes. * To minimize churn in the DOM, only nodes that have changed * are re-rendered. * * By default, rxFor assumes that the object instance identifies the node in the iterable (equality check `===`). * When a function or key is supplied, rxFor uses the result to identify the item node. * * @example * \@Component({ * selector: 'app-root', * template: ` * <app-list-component> * <app-list-item * *rxFor=" * let item of items$; * trackBy: 'id'; * " * > * <div>{{ item.name }}</div> * </app-list-item> * </app-list-component> * ` * }) * export class AppComponent { * items$ = itemService.getItems(); * } * * // OR * * \@Component({ * selector: 'app-root', * template: ` * <app-list-component> * <app-list-item * *rxFor=" * let item of items$; * trackBy: trackItem; * " * > * <div>{{ item.name }}</div> * </app-list-item> * </app-list-component> * ` * }) * export class AppComponent { * items$ = itemService.getItems(); * trackItem = (idx, item) => item.id; * } * * @param trackByFnOrKey */ set trackBy(trackByFnOrKey: keyof T | ((idx: number, i: T) => any)); /** * @description * A `Subject` which emits whenever *rxFor finished rendering a set changes to the view. * This enables developers to perform actions when a list has finished rendering. * The `renderCallback` is useful in situations where you rely on specific DOM properties like the `height` 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: ` * <app-list-component> * <app-list-item * *rxFor=" * let item of items$; * trackBy: trackItem; * renderCallback: itemsRendered; * "> * <div>{{ item.name }}</div> * </app-list-item> * </app-list-component> * ` * }) * export class AppComponent { * items$: Observable<Item[]> = itemService.getItems(); * trackItem = (idx, item) => item.id; * // this emits whenever rxFor finished rendering changes * itemsRendered = new Subject<Item[]>(); * * constructor(elementRef: ElementRef<HTMLElement>) { * itemsRendered.subscribe(() => { * // items are rendered, we can now scroll * elementRef.scrollTo({bottom: 0}); * }) * } * } * * @param {Subject<U>} renderCallback */ set renderCallback(renderCallback: Subject<U>); private get template(); /** @internal */ private strategyInput$; /** @internal */ private observables$; /** @internal */ private _renderCallback; /** @internal */ private readonly values$; /** @internal */ private values; /** @internal */ private readonly strategy$; /** @internal */ private _subscription; /** @internal */ _trackBy: TrackByFunction<T>; /** @internal */ _distinctBy: (a: T, b: T) => boolean; private reconciler; constructor(templateRef: TemplateRef<RxForViewContext<T, U>>); /** @internal */ ngOnInit(): void; /** @internal */ createViewContext(item: T, computedContext: RxListViewComputedContext): RxForViewContext<T, U>; /** @internal */ updateViewContext(item: T, view: EmbeddedViewRef<RxForViewContext<T>>, computedContext: RxListViewComputedContext): void; /** @internal */ ngDoCheck(): void; /** @internal */ ngOnDestroy(): void; /** @internal */ static ngTemplateContextGuard<T, U extends NgIterable<T> = NgIterable<T>, K = keyof T>(dir: RxFor<T, U>, ctx: any): ctx is RxForViewContext<T, U, K>; static ɵfac: i0.ɵɵFactoryDeclaration<RxFor<any, any>, never>; static ɵdir: i0.ɵɵDirectiveDeclaration<RxFor<any, any>, "[rxFor][rxForOf]", never, { "rxForOf": { "alias": "rxForOf"; "required": false; }; "rxForTemplate": { "alias": "rxForTemplate"; "required": false; }; "rxForStrategy": { "alias": "rxForStrategy"; "required": false; }; "renderParent": { "alias": "rxForParent"; "required": false; }; "patchZone": { "alias": "rxForPatchZone"; "required": false; }; "trackBy": { "alias": "rxForTrackBy"; "required": false; }; "renderCallback": { "alias": "rxForRenderCallback"; "required": false; }; }, {}, never, never, true, never>; }