@ngrx/component
Version:
Reactive Extensions for Angular Components
242 lines (235 loc) • 7.79 kB
TypeScript
import * as i0 from '@angular/core';
import { ChangeDetectorRef, OnInit, OnDestroy, TemplateRef, ViewContainerRef, ErrorHandler, PipeTransform } from '@angular/core';
import { Observable } from 'rxjs';
declare abstract class TickScheduler {
abstract schedule(): void;
static ɵfac: i0.ɵɵFactoryDeclaration<TickScheduler, never>;
static ɵprov: i0.ɵɵInjectableDeclaration<TickScheduler>;
}
/**
* Provides rendering functionality regardless of whether `zone.js` is present
* or not. It must be provided at the component/directive level.
*
* @usageNotes
*
* ### Rerender zone-less app on route changes
*
* ```ts
* @Component({
* selector: 'app-root',
* template: '<router-outlet>',
* // 👇 `RenderScheduler` is provided at the component level
* providers: [RenderScheduler],
* changeDetection: ChangeDetectionStrategy.OnPush,
* })
* export class AppComponent implements OnInit {
* constructor(
* private readonly router: Router,
* private readonly renderScheduler: RenderScheduler
* ) {}
*
* ngOnInit(): void {
* this.router.events
* .pipe(filter((e) => e instanceof NavigationEnd))
* .subscribe(() => this.renderScheduler.schedule());
* }
* }
* ```
*
* ### Rerender component on interval
*
* ```ts
* @Component({
* selector: 'app-interval',
* template: '{{ elapsedTime }}ms',
* // 👇 `RenderScheduler` is provided at the component level
* providers: [RenderScheduler],
* changeDetection: ChangeDetectionStrategy.OnPush,
* })
* export class IntervalComponent implements OnInit {
* elapsedTime = 0;
*
* constructor(private readonly renderScheduler: RenderScheduler) {}
*
* ngOnInit(): void {
* setInterval(() => {
* this.elapsedTime += 1000;
* this.renderScheduler.schedule();
* }, 1000);
* }
* }
* ```
*/
declare class RenderScheduler {
private readonly cdRef;
private readonly tickScheduler;
constructor(cdRef: ChangeDetectorRef, tickScheduler: TickScheduler);
/**
* Marks component and its ancestors as dirty.
* It also schedules a new change detection cycle in zone-less mode.
*/
schedule(): void;
static ɵfac: i0.ɵɵFactoryDeclaration<RenderScheduler, never>;
static ɵprov: i0.ɵɵInjectableDeclaration<RenderScheduler>;
}
type Primitive = string | number | bigint | boolean | symbol | null | undefined;
type ObservableOrPromise<T> = Observable<T> | PromiseLike<T>;
type ObservableDictionary<PO> = Required<{
[Key in keyof PO]: Observable<unknown>;
}>;
type PotentialObservableResult<PO, ExtendedResult = never> = PO extends ObservableOrPromise<infer Result> ? Result | ExtendedResult : PO extends Primitive ? PO : keyof PO extends never ? PO : PO extends ObservableDictionary<PO> ? {
[Key in keyof PO]: PO[Key] extends Observable<infer Value> ? Value : never;
} | ExtendedResult : PO;
type LetViewContextValue<PO> = PotentialObservableResult<PO>;
interface LetViewContext<PO> {
/**
* using `$implicit` to enable `let` syntax: `*ngrxLet="obs$; let o"`
*/
$implicit: LetViewContextValue<PO>;
/**
* using `ngrxLet` to enable `as` syntax: `*ngrxLet="obs$ as o"`
*/
ngrxLet: LetViewContextValue<PO>;
/**
* `*ngrxLet="obs$; let e = error"` or `*ngrxLet="obs$; error as e"`
*/
error: any;
/**
* `*ngrxLet="obs$; let c = complete"` or `*ngrxLet="obs$; complete as c"`
*/
complete: boolean;
}
/**
*
* @description
*
* The `*ngrxLet` directive serves a convenient way of binding observables to a view context
* (DOM element's scope). It also helps with several internal processing under the hood.
*
* @usageNotes
*
* ### Displaying Observable Values
*
* ```html
* <ng-container *ngrxLet="number$ as n">
* <app-number [number]="n"></app-number>
* </ng-container>
*
* <ng-container *ngrxLet="number$; let n">
* <app-number [number]="n"></app-number>
* </ng-container>
* ```
*
* ### Tracking Different Observable Events
*
* ```html
* <ng-container *ngrxLet="number$ as n; error as e; complete as c">
* <app-number [number]="n" *ngIf="!e && !c">
* </app-number>
*
* <p *ngIf="e">There is an error: {{ e }}</p>
* <p *ngIf="c">Observable is completed.</p>
* </ng-container>
* ```
*
* ### Combining Multiple Observables
*
* ```html
* <ng-container *ngrxLet="{ users: users$, query: query$ } as vm">
* <app-search-bar [query]="vm.query"></app-search-bar>
* <app-user-list [users]="vm.users"></app-user-list>
* </ng-container>
* ```
*
* ### Using Suspense Template
*
* ```html
* <ng-container *ngrxLet="number$ as n; suspenseTpl: loading">
* <app-number [number]="n"></app-number>
* </ng-container>
*
* <ng-template #loading>
* <p>Loading...</p>
* </ng-template>
* ```
*
* ### Using Aliases for Non-Observable Values
*
* ```html
* <ng-container *ngrxLet="userForm.controls.email as email">
* <input type="text" [formControl]="email" />
*
* <ng-container *ngIf="email.errors && (email.touched || email.dirty)">
* <p *ngIf="email.errors.required">This field is required.</p>
* <p *ngIf="email.errors.email">This field must be an email.</p>
* </ng-container>
* </ng-container>
* ```
*
* @publicApi
*/
declare class LetDirective<PO> implements OnInit, OnDestroy {
private readonly mainTemplateRef;
private readonly viewContainerRef;
private readonly errorHandler;
private readonly renderScheduler;
private isMainViewCreated;
private isSuspenseViewCreated;
private readonly viewContext;
private readonly renderEventManager;
private readonly subscription;
set ngrxLet(potentialObservable: PO);
suspenseTemplateRef?: TemplateRef<unknown>;
constructor(mainTemplateRef: TemplateRef<LetViewContext<PO | undefined>>, viewContainerRef: ViewContainerRef, errorHandler: ErrorHandler, renderScheduler: RenderScheduler);
static ngTemplateContextGuard<PO>(dir: LetDirective<PO>, ctx: unknown): ctx is LetViewContext<PO>;
ngOnInit(): void;
ngOnDestroy(): void;
private renderMainView;
private renderSuspenseView;
static ɵfac: i0.ɵɵFactoryDeclaration<LetDirective<any>, never>;
static ɵdir: i0.ɵɵDirectiveDeclaration<LetDirective<any>, "[ngrxLet]", never, { "ngrxLet": { "alias": "ngrxLet"; "required": false; }; "suspenseTemplateRef": { "alias": "ngrxLetSuspenseTpl"; "required": false; }; }, {}, never, never, true, never>;
}
type PushPipeResult<PO> = PotentialObservableResult<PO, undefined>;
/**
* @description
*
* The `ngrxPush` pipe serves as a drop-in replacement for the `async` pipe.
* It contains intelligent handling of change detection to enable us
* running in zone-full as well as zone-less mode without any changes to the code.
*
* @usageNotes
*
* ### Displaying Observable Values
*
* ```html
* <p>{{ number$ | ngrxPush }}</p>
*
* <ng-container *ngIf="number$ | ngrxPush as n">{{ n }}</ng-container>
*
* <app-number [number]="number$ | ngrxPush"></app-number>
* ```
*
* ### Combining Multiple Observables
*
* ```html
* <code>
* {{ { users: users$, query: query$ } | ngrxPush | json }}
* </code>
* ```
*
* @publicApi
*/
declare class PushPipe implements PipeTransform, OnDestroy {
private readonly errorHandler;
private renderedValue;
private readonly renderScheduler;
private readonly renderEventManager;
private readonly subscription;
constructor(errorHandler: ErrorHandler);
transform<PO>(potentialObservable: PO): PushPipeResult<PO>;
ngOnDestroy(): void;
private setRenderedValue;
static ɵfac: i0.ɵɵFactoryDeclaration<PushPipe, never>;
static ɵpipe: i0.ɵɵPipeDeclaration<PushPipe, "ngrxPush", true>;
}
export { LetDirective, PushPipe, RenderScheduler };