UNPKG

ngx-primeng-toolkit

Version:

A comprehensive TypeScript utility library for Angular component state management, PrimeNG table state management, ng-select helpers, data storage, and memoized HTTP caching. Compatible with Angular 19+ and PrimeNG 19+ (optimized for Angular 20+ and Prime

1,498 lines (1,487 loc) 53 kB
import { HttpClient, HttpContextToken } from '@angular/common/http'; import * as _angular_core from '@angular/core'; import { Signal, DestroyRef } from '@angular/core'; import { TableLazyLoadEvent, Table } from 'primeng/table'; import { z } from 'zod'; import { SelectItem } from 'primeng/api'; import { Subject, Observable } from 'rxjs'; /** * Makes all properties of T nullable (T | null) recursively, handling functions, arrays, and objects * @template Thing - The type to make nullable * @example * ```typescript * type User = { id: number; name: string; email: string; tags: string[] }; * type NullableUser = RecursiveNullable<User>; * // Result: { * // id: number | null; * // name: string | null; * // email: string | null; * // tags: (string | null)[] | null; * // } * ``` */ type RecursiveNullable<Thing> = Thing extends Function ? Thing : Thing extends Array<infer InferredArrayMember> ? RecursiveNullableArray<InferredArrayMember> : Thing extends Record<string, any> ? RecursiveNullableObject<Thing> : Exclude<Thing, undefined> | null; type RecursiveNullableObject<Thing extends object> = { [Key in keyof Thing]: RecursiveNullable<Thing[Key]>; }; interface RecursiveNullableArray<Thing> extends Array<RecursiveNullable<Thing>> { } /** * Makes all properties of T nullish (T | null | undefined) * @template T - The base type * @example * ```typescript * type User = { id: number; name: string }; * type NullishUser = Nullish<User>; * // Result: { id: number | null | undefined; name: string | null | undefined } * ``` */ type Nullish<T> = { [P in keyof T]: Exclude<T[P], null | undefined> | null | undefined; }; /** * Makes all properties of T nullish (T | null | undefined) recursively, handling functions, arrays, and objects * @template Thing - The type to make nullish * @example * ```typescript * type User = { id: number; profile: { name: string; age: number }; tags: string[] }; * type NullishUser = RecursiveNullish<User>; * // Result: { * // id: number | null | undefined; * // profile: { * // name: string | null | undefined; * // age: number | null | undefined * // } | null | undefined; * // tags: (string | null | undefined)[] | null | undefined; * // } * ``` */ type RecursiveNullish<Thing> = Thing extends Function ? Thing : Thing extends Array<infer InferredArrayMember> ? RecursiveNullishArray<InferredArrayMember> : Thing extends Record<string, any> ? RecursiveNullishObject<Thing> : Exclude<Thing, null | undefined> | null | undefined; type RecursiveNullishObject<Thing extends object> = { [Key in keyof Thing]: RecursiveNullish<Thing[Key]>; }; interface RecursiveNullishArray<Thing> extends Array<RecursiveNullish<Thing>> { } /** * Makes all properties optional recursively, useful for partial updates, handling functions, arrays, and objects * @template Thing - The type to make recursively partial * @example * ```typescript * type User = { * id: number; * profile: { name: string; age: number }; * settings: { theme: string; notifications: boolean }; * tags: string[]; * }; * type PartialUser = RecursivePartial<User>; * // Result: { * // id?: number | undefined; * // profile?: { name?: string | undefined; age?: number | undefined } | undefined; * // settings?: { theme?: string | undefined; notifications?: boolean | undefined } | undefined; * // tags?: (string | undefined)[] | undefined; * // } * ``` */ type RecursivePartial<Thing> = Thing extends Function ? Thing : Thing extends Array<infer InferredArrayMember> ? RecursivePartialArray<InferredArrayMember> : Thing extends object ? RecursivePartialObject<Thing> : Thing | undefined; type RecursivePartialObject<Thing> = { [Key in keyof Thing]?: RecursivePartial<Thing[Key]>; }; interface RecursivePartialArray<Thing> extends Array<RecursivePartial<Thing>> { } /** * Enumeration for manipulation types in component operations * Used for tracking the current operation state in component management * * @example * ```typescript * // In a component * currentOperation: ManipulationType = ManipulationType.Create; * * // Check operation type * if (this.currentOperation === ManipulationType.Update) { * // Handle update logic * } * ``` */ declare enum ManipulationType { /** Creating a new item */ Create = "Create", /** Updating an existing item */ Update = "Update", /** Creating a child item */ CreateChild = "Create Child", /** Deleting an item */ Delete = "Delete", /** Viewing item details */ View = "View", /** Saving an item */ Save = "Save" } /** * Key-value pair type for common data structures * @template K The type of the key * @template D The type of the data */ interface KeyData<K, D> { key: K; data: D; } /** * Common API response wrapper type * @template T The type of the data payload */ interface ApiResponse<T> { data: T; message?: string; status: number; success: boolean; } /** * Pagination metadata interface */ interface PaginationMeta { currentPage: number; totalPages: number; totalItems: number; itemsPerPage: number; hasNextPage: boolean; hasPreviousPage: boolean; } /** * Paginated response type * @template T The type of the data items */ interface PaginatedResponse<T> { data: T[]; meta: PaginationMeta; } /** * Query parameters for pagination */ interface PaginationParams { page?: number; limit?: number; offset?: number; } /** * Common sort parameters */ interface SortParams { sortBy?: string; sortOrder?: "asc" | "desc"; } /** * Combined query parameters for API requests */ type QueryParams = Record<string, string | number | boolean> & Partial<PaginationParams> & Partial<SortParams>; /** * String filter types for PrimeNG table filtering */ type StringFilterType = "startsWith" | "notStartsWith" | "endsWith" | "notEndsWith" | "contains" | "notContains"; /** * Numeric filter types for PrimeNG table filtering */ type NumericFilterType = "equals" | "notEquals" | "greaterThan" | "lessThan" | "greaterThanOrEqual" | "lessThanOrEqual"; /** * Boolean filter types for PrimeNG table filtering */ type BooleanFilterType = Extract<NumericFilterType, "equals" | "notEquals">; /** * Combined filter types */ type FilterType = StringFilterType | NumericFilterType; /** * Filter type mappings for backend API */ type FilterTypeMapped = "starts" | "!starts" | "ends" | "!ends" | "like" | "!like" | "=" | "!=" | ">" | "<" | ">=" | "<="; /** * PrimeNG table header configuration interface */ interface PrimeNgTableHeader { identifier: { label?: string; field: string; hasSort?: boolean; isBoolean?: boolean; isNested?: boolean; isDate?: boolean; isDateTime?: boolean; styleClass?: string; }; filter?: { type: "text" | "numeric" | "boolean" | "date" | "dropdown" | "multiselect"; placeholder?: string; matchModeOptions?: any[]; defaultMatchMode: FilterType; ariaLabel?: string; colspan?: number; styleClass?: Record<string, string>; }; } /** * Dynamic query DTO interface */ interface DynamicQueryDto { size: number; page: number; filter: DynamicQueryFilterDto[]; sort: DynamicQuerySortDto[]; } /** * Filter DTO for dynamic queries */ interface DynamicQueryFilterDto { field: string; value: string; type: FilterTypeMapped; } /** * Sort DTO for dynamic queries */ interface DynamicQuerySortDto { field: string; dir: "asc" | "desc"; } /** * Paged data response interface */ interface DynamicQueryPagedDataResponse<T> { data: T[]; last_page: number; last_row: number; } /** * Paged data response interface for simple pagination */ interface PagedDataResponse<T> { payload: T[]; totalCount: number; } /** * Internal table state interface for dynamic table */ interface PrimeNgTableState<T> { data: Array<T>; isLoading: boolean; size: number; page: number; totalRecords: number; filter: DynamicQueryFilterDto[]; sort: DynamicQuerySortDto[]; } /** * Internal state interface for paged table */ interface PrimeNgPagedTableState<T> { data: Array<T>; isLoading: boolean; totalRecords: number; limit: number; page: number; } /** * Query DTO interface for paged data requests */ interface PagedDataQueryDto { limit: number; page: number; } /** * Query parameters type for additional HTTP request parameters */ type PrimeNgTableStateHelperQueryParam = Record<string, string | number | boolean>; /** * Zod schema for dynamic query response validation */ declare const dynamicQueryResponseZodSchema: z.ZodObject<{ data: z.ZodArray<z.ZodAny, "many">; last_page: z.ZodNumber; last_row: z.ZodNumber; }, "strip", z.ZodTypeAny, { data: any[]; last_page: number; last_row: number; }, { data: any[]; last_page: number; last_row: number; }>; /** * Zod schema for paged data response validation */ declare const PagedDataResponseZodSchema: z.ZodObject<{ payload: z.ZodArray<z.ZodAny, "many">; totalCount: z.ZodNumber; }, "strip", z.ZodTypeAny, { payload: any[]; totalCount: number; }, { payload: any[]; totalCount: number; }>; /** * Error response interface */ interface ErrorResponse { error: string; message: string; statusCode: number; timestamp: string; } /** * Creates a key-value pair object * @param key The key value * @param data The data value * @returns KeyData object */ declare function createKeyData<K, D>(key: K, data: D): KeyData<K, D>; /** * Type guard to check if a response is an API response * @param response The response to check * @returns true if response is ApiResponse, false otherwise */ declare function isApiResponse<T>(response: any): response is ApiResponse<T>; /** * Type guard to check if a response is paginated * @param response The response to check * @returns true if response is PaginatedResponse, false otherwise */ declare function isPaginatedResponse<T>(response: any): response is PaginatedResponse<T>; /** * Type guard to check if a response is a simple paged response * @param response The response to check * @returns true if response is PagedDataResponse, false otherwise */ declare function isSimplePagedResponse<T>(response: any): response is PagedDataResponse<T>; /** * Type guard to check if a response is a dynamic query response * @param response The response to check * @returns true if response is PagedDataResponse, false otherwise */ declare function isDynamicQueryResponse<T>(response: any): response is DynamicQueryPagedDataResponse<T>; type NestableColumn = { isNested?: boolean; }; /** * Options for creating PrimeNgDynamicTableStateHelper */ type PrimeNgDynamicTableStateOpts = { url: string; httpClient: HttpClient; skipLoadingSpinner?: boolean; }; /** * PrimeNG Dynamic Table State Helper class for managing table state with lazy loading, filtering, and sorting * * This helper provides advanced table functionality including: * - Lazy loading with pagination * - Column filtering with multiple filter types * - Multi-column sorting * - State management with NgRx Signals * - Automatic API integration * - Route parameter support * - Query parameter management * * @example * ```typescript * const tableState = PrimeNgDynamicTableStateHelper.create<User>({ * url: '/api/users', * httpClient: this.httpClient * }); * * // In template * <p-table [value]="tableState.data()" * [lazy]="true" * [loading]="tableState.isLoading()" * [totalRecords]="tableState.totalRecords()" * (onLazyLoad)="tableState.onLazyLoad($event)"> * </p-table> * ``` */ declare class PrimeNgDynamicTableStateHelper<T> { #private; private url; private readonly httpClient; private readonly state; private urlWithOutRouteParam; private skipLoadingSpinner; readonly uniqueKey: Signal<string>; readonly totalRecords: Signal<number>; readonly isLoading: Signal<boolean>; readonly data: Signal<Array<T>>; private constructor(); /** * Creates a new instance of PrimeNgDynamicTableStateHelper * @param options - Configuration options * @returns New instance of PrimeNgDynamicTableStateHelper */ static create<T>(options: PrimeNgDynamicTableStateOpts): PrimeNgDynamicTableStateHelper<T>; /** * Sets whether to skip the loading spinner * @param skip - Whether to skip the loading spinner * @returns This instance for method chaining */ setSkipLoadingSpinner(skip: boolean): this; /** * Sets the unique key field for table rows * @param newUniqueKey - The field name to use as unique identifier * @returns This instance for method chaining */ setUniqueKey(newUniqueKey: string): this; /** * Updates the API URL * @param newUrl - The new API URL * @returns This instance for method chaining */ setUrl(newUrl: string): this; /** * Appends a route parameter to the URL * @param newRouteParam - The route parameter to append * @returns This instance for method chaining */ setRouteParam(newRouteParam: string): this; /** * Patches existing query parameters * @param value - Query parameters to merge * @returns This instance for method chaining */ patchQueryParams(value: PrimeNgTableStateHelperQueryParam): this; /** * Removes a specific query parameter * @param key - The key to remove * @returns This instance for method chaining */ removeQueryParam(key: string): this; /** * Sets all query parameters (replaces existing) * @param newQueryParams - New query parameters * @returns This instance for method chaining */ setQueryParams(newQueryParams: PrimeNgTableStateHelperQueryParam): this; /** * Handles PrimeNG table lazy load events * @param event - The lazy load event from PrimeNG table */ onLazyLoad(event: TableLazyLoadEvent): Promise<void>; /** * Clears table data and resets to first page * @param table - Optional PrimeNG Table reference to reset */ clearTableData(table?: Table): Promise<void>; /** * Manually triggers data refresh with current state */ refresh(): Promise<void>; /** * Fetches data from the API */ private fetchData; /** * Builds the DTO for API requests */ private dtoBuilder; /** * Maps PrimeNG filters to API filter format */ private filterMapper; /** * Maps PrimeNG filter match modes to API filter types */ private evaluateInput; } /** * Options for creating PrimengPagedDataTableStateHelper */ type PrimeNgPagedTableStateOpts = { url: string; httpClient: HttpClient; skipLoadingSpinner?: boolean; }; /** * Simple paged data table state helper for basic pagination without filtering * * This helper provides basic table functionality including: * - Simple pagination (page and limit only) * - Basic state management with NgRx Signals * - API integration for paged data * - Route parameter support * - Query parameter management * * Use this when you need simple pagination without complex filtering and sorting. * For advanced features, use PrimeNgDynamicTableStateHelper instead. * * @example * ```typescript * const tableState = PrimengPagedDataTableStateHelper.create<Product>({ * url: '/api/products', * httpClient: this.httpClient * }); * * // In template * <p-table [value]="tableState.data()" * [lazy]="true" * [loading]="tableState.isLoading()" * [totalRecords]="tableState.totalRecords()" * (onLazyLoad)="tableState.onLazyLoad($event)"> * </p-table> * ``` */ declare class PrimeNgPagedDataTableStateHelper<T> { #private; private url; private readonly httpClient; private urlWithOutRouteParam; private skipLoadingSpinner; readonly uniqueKey: Signal<string>; readonly totalRecords: Signal<number>; readonly isLoading: Signal<boolean>; readonly data: Signal<Array<T>>; readonly currentPage: Signal<number>; readonly currentPageSize: Signal<number>; private constructor(); /** * Creates a new instance of PrimengPagedDataTableStateHelper * @param option - Configuration options * @returns New instance of PrimengPagedDataTableStateHelper */ static create<T>(option: PrimeNgPagedTableStateOpts): PrimeNgPagedDataTableStateHelper<T>; /** * Creates a new instance without initial URL (can be set later) * @param option - Configuration options without URL * @returns New instance of PrimengPagedDataTableStateHelper */ static createWithBlankUrl<T>(option: Omit<PrimeNgPagedTableStateOpts, "url">): PrimeNgPagedDataTableStateHelper<T>; /** * Sets whether to skip the loading spinner * @param skip - Whether to skip the loading spinner * @returns This instance for method chaining */ setSkipLoadingSpinner(skip: boolean): this; /** * Sets the unique key field for table rows * @param newUniqueKey - The field name to use as unique identifier * @returns This instance for method chaining */ setUniqueKey(newUniqueKey: string): this; /** * Updates the API URL * @param newUrl - The new API URL * @returns This instance for method chaining */ setUrl(newUrl: string): this; /** * Appends a route parameter to the URL * @param newRouteParam - The route parameter to append * @returns This instance for method chaining */ setRouteParam(newRouteParam: string): this; /** * Patches existing query parameters * @param value - Query parameters to merge * @returns This instance for method chaining */ patchQueryParams(value: PrimeNgTableStateHelperQueryParam): this; /** * Removes a specific query parameter * @param key - The key to remove * @returns This instance for method chaining */ removeQueryParam(key: string): this; /** * Removes all query parameters * @returns This instance for method chaining */ removeAllQueryParams(): this; /** * Sets all query parameters (replaces existing) * @param newQueryParams - New query parameters * @returns This instance for method chaining */ setQueryParams(newQueryParams: PrimeNgTableStateHelperQueryParam): this; /** * Handles PrimeNG table lazy load events * @param event - The lazy load event from PrimeNG table */ onLazyLoad(event: TableLazyLoadEvent): Promise<void>; /** * Clears table data and resets to first page * @param table - Optional PrimeNG Table reference to reset */ clearTableData(table?: Table): Promise<void>; /** * Manually triggers data refresh with current state */ refresh(): Promise<void>; /** * Fetches data from the API */ private fetchData; /** * Builds the DTO for API requests */ private dtoBuilder; } /** * HTTP Context Token to skip loading spinner on HTTP requests * Usage: Set this token to true in HttpContext to skip showing loading spinner * * @example * ```typescript * const context = new HttpContext().set(SkipLoadingSpinner, true); * this.httpClient.get('/api/data', { context }); * ``` */ declare const SkipLoadingSpinner: HttpContextToken<boolean>; /** * Creates PrimeNG SelectItem array for numeric filter match modes * @param styleClass - CSS class for styling the options * @param disabled - Whether the options should be disabled * @returns Array of SelectItem for numeric filters */ declare function createPrimengNumberMatchModes(styleClass?: string, disabled?: boolean): SelectItem<NumericFilterType>[]; /** * Creates PrimeNG SelectItem array for string filter match modes * @param styleClass - CSS class for styling the options * @param disabled - Whether the options should be disabled * @returns Array of SelectItem for string filters */ declare function createPrimengStringMatchModes(styleClass?: string, disabled?: boolean): SelectItem<StringFilterType>[]; /** * Creates a complete table header configuration for text columns * @param field - The field name for the column * @param label - Display label for the column header * @param options - Additional configuration options * @returns Complete PrimeNgTableHeader configuration */ declare function createTextColumn(field: string, label: string, options?: { hasSort?: boolean; hasFilter?: boolean; placeholder?: string; matchModeOptions?: SelectItem<StringFilterType>[]; defaultMatchMode?: StringFilterType; styleClass?: string; filterStyleClass?: Record<string, string>; } & NestableColumn): PrimeNgTableHeader; /** * Creates a complete table header configuration for numeric columns * @param field - The field name for the column * @param label - Display label for the column header * @param options - Additional configuration options * @returns Complete PrimeNgTableHeader configuration */ declare function createNumericColumn(field: string, label: string, options?: { hasSort?: boolean; hasFilter?: boolean; placeholder?: string; matchModeOptions?: SelectItem<NumericFilterType>[]; defaultMatchMode?: NumericFilterType; styleClass?: string; filterStyleClass?: Record<string, string>; } & NestableColumn): PrimeNgTableHeader; /** * Creates a complete table header configuration for boolean columns * @param field - The field name for the column * @param label - Display label for the column header * @param options - Additional configuration options * @returns Complete PrimeNgTableHeader configuration */ declare function createBooleanColumn(field: string, label: string, options?: { hasSort?: boolean; hasFilter?: boolean; styleClass?: string; filterStyleClass?: Record<string, string>; } & NestableColumn): PrimeNgTableHeader; /** * Creates a complete table header configuration for date columns * @param field - The field name for the column * @param label - Display label for the column header * @param options - Additional configuration options * @returns Complete PrimeNgTableHeader configuration */ declare function createDateColumn(field: string, label: string, options?: { hasSort?: boolean; hasFilter?: boolean; placeholder?: string; styleClass?: string; filterStyleClass?: Record<string, string>; } & NestableColumn): PrimeNgTableHeader; /** * Creates a complete table header configuration for dropdown columns * @param field - The field name for the column * @param label - Display label for the column header * @param dropdownOptions - Options for the dropdown filter * @param options - Additional configuration options * @returns Complete PrimeNgTableHeader configuration */ declare function createDropdownColumn(field: string, label: string, dropdownOptions: SelectItem[], options?: { hasSort?: boolean; hasFilter?: boolean; placeholder?: string; styleClass?: string; filterStyleClass?: Record<string, string>; }): PrimeNgTableHeader; /** * Creates a complete table header configuration for multiselect columns * @param field - The field name for the column * @param label - Display label for the column header * @param multiselectOptions - Options for the multiselect filter * @param options - Additional configuration options * @returns Complete PrimeNgTableHeader configuration */ declare function createMultiselectColumn(field: string, label: string, multiselectOptions: SelectItem[], options?: { hasSort?: boolean; hasFilter?: boolean; placeholder?: string; styleClass?: string; filterStyleClass?: Record<string, string>; }): PrimeNgTableHeader; /** * Creates a simple table header configuration without filtering * @param field - The field name for the column * @param label - Display label for the column header * @param options - Additional configuration options * @returns Simple PrimeNgTableHeader configuration */ declare function createSimpleColumn(field: string, label: string, options?: { hasSort?: boolean; styleClass?: string; } & NestableColumn): PrimeNgTableHeader; /** * Utility function to merge multiple table header configurations * @param headers - Array of table header configurations * @returns Array of merged headers */ declare function mergeTableHeaders(...headers: PrimeNgTableHeader[]): PrimeNgTableHeader[]; /** * Utility function to create boolean SelectItem options * @param trueLabel - Label for true value * @param falseLabel - Label for false value * @returns Array of SelectItem for boolean values */ declare function createBooleanSelectItems(trueLabel?: string, falseLabel?: string): SelectItem[]; /** * Utility function to create status SelectItem options * @param statusOptions - Object mapping status values to labels * @returns Array of SelectItem for status values */ declare function createStatusSelectItems(statusOptions: Record<string | number, string>): SelectItem[]; /** * Utility function to remove null and undefined values from an object * * This is particularly useful when setting query parameters, as null/undefined * values should typically be filtered out before sending to APIs. * * @param o The object to clean * @returns A new object with null and undefined values removed * * @example * ```typescript * const queryParams = { * name: 'John', * age: null, * email: 'john@example.com', * phone: undefined * }; * * const cleaned = cleanNullishFromObject(queryParams); * // Result: { name: 'John', email: 'john@example.com' } * * // Use case with table state * this.tableState.setQueryParams(cleanNullishFromObject(queryParams)); * ``` */ declare function cleanNullishFromObject(o: object): Record<string, any>; declare function hasNullishInObject(obj: object): boolean; declare function routeParamConcat(baseUrl: string, routeParam: number | string): string; declare function binarySearch<TItem>(arr: TItem[], val: TItem): number; declare function emptyCallback(): void; declare function nullableKeyData<TKey, TData>(key: TKey | null, data: TData | null): KeyData<TKey, TData> | null; declare class ReloadNotification { static create(): ReloadNotification; } /** * A generic class for memoizing data storage with HTTP caching capabilities * Provides methods to load and cache single data objects or arrays with automatic loading states * * @template T The type of data to be stored and managed * * @example * ```typescript * interface User { id: number; name: string; } * * const userStorage = new MemoizedDataStorage<User>(httpClient); * await userStorage.loadSingleData('/api/user/1'); * console.log(userStorage.singleData()); // User data or null * * const usersStorage = new MemoizedDataStorage<User>(httpClient); * await usersStorage.loadMultipleData('/api/users'); * console.log(usersStorage.multipleData()); // Array of User data * ``` */ declare class MemoizedDataStorage<T> { #private; readonly httpClient: HttpClient; private skipLoadingSpinner; /** * Creates a new instance of MemoizedDataStorage * @param httpClient Angular HttpClient instance for making HTTP requests * @param skipLoadingSpinner Whether to skip the loading spinner for HTTP requests */ constructor(httpClient: HttpClient, skipLoadingSpinner?: boolean); /** * Sets whether to skip the loading spinner for HTTP requests * @param skip Whether to skip the loading spinner * @returns This instance for method chaining */ setSkipLoadingSpinner(skip: boolean): this; /** * Read-only signal containing single data object or null */ readonly singleData: _angular_core.Signal<T | null>; /** * Read-only signal containing array of data objects */ readonly multipleData: _angular_core.Signal<T[]>; /** * Read-only signal indicating whether a request is currently loading */ readonly isLoading: _angular_core.Signal<boolean>; /** * Disables memoization for the next read operation and clears cached data * This forces the next loadSingleData or loadMultipleData call to fetch fresh data * * @example * ```typescript * const storage = new MemoizedDataStorage<User>(httpClient); * await storage.loadSingleData('/api/user/1'); // Fetches data * await storage.loadSingleData('/api/user/1'); // Returns cached data * * storage.disableMemoizationOnNextRead(); * await storage.loadSingleData('/api/user/1'); // Fetches fresh data * ``` */ disableMemoizationOnNextRead(): void; /** * Loads a single data object from the specified URL with optional query parameters * Uses memoization to avoid redundant requests unless explicitly disabled * * @param url The URL to fetch data from * @param queryParams Optional query parameters to include in the request * @returns Promise that resolves when the data is loaded * @throws Error if the HTTP request fails * * @example * ```typescript * const storage = new MemoizedDataStorage<User>(httpClient); * await storage.loadSingleData('/api/user/1', { include: 'profile' }); * const user = storage.singleData(); // User data or null * ``` */ loadSingleData(url: string, queryParams?: Record<string, string | number>): Promise<void>; /** * Loads multiple data objects from the specified URL with optional query parameters * Uses memoization to avoid redundant requests unless explicitly disabled * * @param url The URL to fetch data from * @param queryParams Optional query parameters to include in the request * @returns Promise that resolves when the data is loaded * @throws Error if the HTTP request fails * * @example * ```typescript * const storage = new MemoizedDataStorage<User>(httpClient); * await storage.loadMultipleData('/api/users', { page: 1, limit: 10 }); * const users = storage.multipleData(); // Array of User data * ``` */ loadMultipleData(url: string, queryParams?: Record<string, string | number>): Promise<void>; /** * Clears all cached data and resets the storage to initial state * * @example * ```typescript * const storage = new MemoizedDataStorage<User>(httpClient); * await storage.loadSingleData('/api/user/1'); * storage.clear(); // Clears cached data * console.log(storage.singleData()); // null * console.log(storage.multipleData()); // [] * ``` */ clear(): void; /** * Checks if single data is currently cached * @returns true if single data is cached, false otherwise */ hasSingleData(): boolean; /** * Checks if multiple data is currently cached * @returns true if multiple data is cached (non-empty array), false otherwise */ hasMultipleData(): boolean; } /** * A reactive state management class for Angular components using signals * Provides common component state properties and computed values * * @example * ```typescript * @Component({ * selector: 'app-user-management', * template: ` * <h2>{{ componentState.componentTitleWithManipulationType() }}</h2> * <p-button * [loading]="componentState.isAnyAjaxOperationRunning()" * [disabled]="componentState.isAnyAjaxOperationRunning()"> * Save * </p-button> * ` * }) * export class UserManagementComponent { * componentState = new ComponentState() * .updateComponentTitle('User') * .updateCheckBoxSelectionStatus(true); * } * ``` */ declare class ComponentState { readonly isAjaxDataIncoming: _angular_core.WritableSignal<boolean>; readonly enableCheckBoxSelection: _angular_core.WritableSignal<boolean>; readonly isSelectableRowEnabled: _angular_core.WritableSignal<boolean>; readonly isAjaxRequestOutgoing: _angular_core.WritableSignal<boolean>; readonly hasMultipleSelection: _angular_core.WritableSignal<boolean>; readonly isCreateOrUpdateDialogOpen: _angular_core.WritableSignal<boolean>; readonly isUpdateDialogOpen: _angular_core.WritableSignal<boolean>; readonly isCreateDialogOpen: _angular_core.WritableSignal<boolean>; readonly manipulationType: _angular_core.WritableSignal<ManipulationType>; readonly componentTitle: _angular_core.WritableSignal<string>; /** * Updates the component title * @param componentTitle - The new title for the component * @returns This instance for method chaining */ updateComponentTitle: (componentTitle: string) => this; /** * Updates the multiple selection status * @param newStatus - Whether multiple selection is enabled * @returns This instance for method chaining */ updateMultipleSelectionStatus: (newStatus: boolean) => this; /** * Updates the checkbox selection status * @param newStatus - Whether checkbox selection is enabled * @returns This instance for method chaining */ updateCheckBoxSelectionStatus: (newStatus: boolean) => this; /** * Updates the selectable row status * @param newStatus - Whether row selection is enabled * @returns This instance for method chaining */ updateSelectableRowStatus: (newStatus: boolean) => this; /** * Updates the manipulation type (Create, Update, Delete, View) * @param type - The manipulation type * @returns This instance for method chaining */ updateManipulationType: (type: ManipulationType) => this; /** * Sets the incoming Ajax data status * @param status - Whether Ajax data is incoming * @returns This instance for method chaining */ setAjaxDataIncoming: (status: boolean) => this; /** * Sets the outgoing Ajax request status * @param status - Whether Ajax request is outgoing * @returns This instance for method chaining */ setAjaxRequestOutgoing: (status: boolean) => this; /** * Sets the create or update dialog open status * @param status - Whether the dialog is open * @returns This instance for method chaining */ setCreateOrUpdateDialogOpen: (status: boolean) => this; /** * Sets the update dialog open status * @param status - Whether the update dialog is open * @returns This instance for method chaining */ setUpdateDialogOpen: (status: boolean) => this; /** * Sets the create dialog open status * @param status - Whether the create dialog is open * @returns This instance for method chaining */ setCreateDialogOpen: (status: boolean) => this; /** * Computed signal that combines component title with manipulation type */ readonly componentTitleWithManipulationType: _angular_core.Signal<string>; /** * Computed signal that indicates if component is in update state */ readonly isOnUpdateState: _angular_core.Signal<boolean>; /** * Computed signal that indicates if component is in create state */ readonly isOnCreateState: _angular_core.Signal<boolean>; /** * Computed signal that indicates if component is in delete state */ readonly isOnDeleteState: _angular_core.Signal<boolean>; /** * Computed signal that indicates if component is in view state */ readonly isOnViewState: _angular_core.Signal<boolean>; /** * Computed signal that indicates if any Ajax operation is currently running */ readonly isAnyAjaxOperationRunning: _angular_core.Signal<boolean>; /** * Computed signal that indicates if any dialog is open */ readonly isAnyDialogOpen: _angular_core.Signal<boolean>; /** * Resets all state to default values * @returns This instance for method chaining */ reset: () => this; } /** * A generic component data storage class using Angular signals * Provides reactive data management for both single objects and arrays * * @template T The type of data to be stored and managed * * @example * ```typescript * interface User { * id: number; * name: string; * email: string; * } * * @Component({ * selector: 'app-user-list', * template: ` * <!-- Single user display --> * @if (dataStorage.singleData(); as user) { * <div> * <h3>{{ user.name }}</h3> * <p>{{ user.email }}</p> * </div> * } * * <!-- Multiple users display --> * @for (user of dataStorage.multipleData(); track user.id) { * <div>{{ user.name }} - {{ user.email }}</div> * } * ` * }) * export class UserListComponent { * dataStorage = new ComponentDataStorage<User>(); * * ngOnInit() { * // Set initial data * this.dataStorage * .updateSingleData({ id: 1, name: 'John', email: 'john@example.com' }) * .updateMultipleData([ * { id: 1, name: 'John', email: 'john@example.com' }, * { id: 2, name: 'Jane', email: 'jane@example.com' } * ]); * } * } * ``` */ declare class ComponentDataStorage<T> { readonly singleData: _angular_core.WritableSignal<T | null>; readonly multipleData: _angular_core.WritableSignal<T[]>; /** * Patches multiple data by appending new data to the existing array * @param newData - Array of new data to append * @returns This instance for method chaining * * @example * ```typescript * const storage = new ComponentDataStorage<User>(); * storage.updateMultipleData([{ id: 1, name: 'John' }]); * storage.patchMultipleData([{ id: 2, name: 'Jane' }]); * // Result: [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }] * ``` */ patchMultipleData(newData: Array<T>): this; /** * Patches single data by merging new properties with existing data * If no existing data, creates new object with provided data * @param newData - Partial data to merge with existing single data * @returns This instance for method chaining * * @example * ```typescript * const storage = new ComponentDataStorage<User>(); * storage.updateSingleData({ id: 1, name: 'John', email: 'john@example.com' }); * storage.patchSingleData({ email: 'john.doe@example.com' }); * // Result: { id: 1, name: 'John', email: 'john.doe@example.com' } * ``` */ patchSingleData(newData: Partial<T>): this; /** * Replaces the entire multiple data array * @param newData - New array of data to replace existing data * @returns This instance for method chaining */ updateMultipleData(newData: Array<T>): this; /** * Replaces the single data object * @param newData - New data object or null to replace existing data * @returns This instance for method chaining */ updateSingleData(newData: T | null): this; /** * Adds a single item to the multiple data array * @param item - Single item to add to the array * @returns This instance for method chaining */ addToMultipleData(item: T): this; /** * Removes an item from the multiple data array based on a predicate function * @param predicate - Function that returns true for items to remove * @returns This instance for method chaining * * @example * ```typescript * storage.removeFromMultipleData(user => user.id === 1); * ``` */ removeFromMultipleData(predicate: (item: T) => boolean): this; /** * Updates an item in the multiple data array based on a predicate function * @param predicate - Function that returns true for items to update * @param updateFn - Function that returns the updated item * @returns This instance for method chaining * * @example * ```typescript * storage.updateItemInMultipleData( * user => user.id === 1, * user => ({ ...user, name: 'Updated Name' }) * ); * ``` */ updateItemInMultipleData(predicate: (item: T) => boolean, updateFn: (item: T) => T): this; /** * Clears all data (both single and multiple) * @returns This instance for method chaining */ clearAll(): this; /** * Clears only the single data * @returns This instance for method chaining */ clearSingleData(): this; /** * Clears only the multiple data * @returns This instance for method chaining */ clearMultipleData(): this; /** * Checks if single data exists (is not null) * @returns true if single data exists, false otherwise */ hasSingleData(): boolean; /** * Checks if multiple data has items * @returns true if multiple data array has items, false if empty */ hasMultipleData(): boolean; /** * Gets the count of items in multiple data * @returns Number of items in the multiple data array */ getMultipleDataCount(): number; /** * Finds an item in the multiple data array * @param predicate - Function that returns true for the item to find * @returns The found item or undefined */ findInMultipleData(predicate: (item: T) => boolean): T | undefined; /** * Checks if an item exists in the multiple data array * @param predicate - Function that returns true for the item to check * @returns true if item exists, false otherwise */ existsInMultipleData(predicate: (item: T) => boolean): boolean; } /** * Configuration options for NgSelectHelper */ type NgSelectHelperOpts = { ajaxUrl: string; httpClient: HttpClient; destroyRef: DestroyRef; usePostRequest: boolean; limit?: number; useCache?: boolean; skipLoadingSpinner?: boolean; }; /** * Reset options for NgSelectHelper */ type NgSelectHelperResetOpts = { resetQueryParams: boolean; resetBody: boolean; resetCache: boolean; }; /** * Query parameter type for NgSelectHelper */ type NgSelectHelperQueryParam = Record<string, string | number | boolean>; /** * Body type for NgSelectHelper POST requests */ type NgSelectHelperBody = Array<string | number | boolean | null | Record<string, string | number | boolean | null>> | Record<string, string | number | boolean | null | Array<string | number | boolean | null | Record<string, string | number | boolean | null>>>; /** * Paged data response specifically for ng-select */ declare class NgSelectPagedDataResponse<TData> { readonly payload: Array<TData>; readonly totalCount: number; constructor(payload: Array<TData>, totalCount: number); } /** * Zod schema for validating ng-select paged response */ declare const NgSelectPagedDataResponseZodSchema: z.ZodObject<{ payload: z.ZodArray<z.ZodAny, "many">; totalCount: z.ZodNumber; }, "strip", z.ZodTypeAny, { payload: any[]; totalCount: number; }, { payload: any[]; totalCount: number; }>; /** * NgSelectHelper class for managing ng-select components with HTTP data loading, * pagination, caching, and search functionality using Angular signals * * @template TData The type of data items in the select options * * @example * ```typescript * interface User { * id: number; * name: string; * email: string; * } * * @Component({ * selector: 'app-user-select', * template: ` * <ng-select * [items]="selectHelper.loadedData().payload" * bindLabel="name" * bindValue="id" * [loading]="selectHelper.isLoading()" * [typeahead]="selectHelper.inputSubject" * (open)="selectHelper.onOpen()" * (close)="selectHelper.onClose()" * (clear)="selectHelper.onClear()" * (scrollToEnd)="selectHelper.onScrollToEnd()"> * </ng-select> * ` * }) * export class UserSelectComponent implements OnInit { * private httpClient = inject(HttpClient); * private destroyRef = inject(DestroyRef); * * selectHelper = NgSelectHelper.create<User>({ * ajaxUrl: '/api/users', * httpClient: this.httpClient, * destroyRef: this.destroyRef, * usePostRequest: false, * limit: 20 * }); * * ngOnInit() { * this.selectHelper.init(); * } * } * ``` */ declare class NgSelectHelper<TData> { #private; private ajaxUrl; private readonly httpClient; private readonly destroyRef; readonly usePostRequest: boolean; private readonly useCache; private skipLoadingSpinner; constructor(ajaxUrl: string, httpClient: HttpClient, destroyRef: DestroyRef, usePostRequest?: boolean, limit?: number, useCache?: boolean, skipLoadingSpinner?: boolean); readonly inputSubject: Subject<string>; readonly ajaxError$: Observable<Error>; readonly loadedData: _angular_core.Signal<NgSelectPagedDataResponse<TData>>; readonly isLoading: _angular_core.Signal<boolean>; private runningApiReq; /** * Creates a new instance of NgSelectHelper * @param options Configuration options * @returns New NgSelectHelper instance */ static create<T>({ ajaxUrl, httpClient, destroyRef, usePostRequest, limit, useCache, skipLoadingSpinner }: NgSelectHelperOpts): NgSelectHelper<T>; /** * Sets whether to skip the loading spinner for HTTP requests * @param skip Whether to skip the loading spinner * @returns This instance for method chaining */ setSkipLoadingSpinner(skip: boolean): this; /** * Sets the debounce time for search input in seconds * @param debounceTimeInSecond Debounce time in seconds * @returns This instance for method chaining */ setDebounceTimeInSecond(debounceTimeInSecond: number): this; /** * Patches the request body (only works with POST requests) * @param value Body data to merge * @returns This instance for method chaining */ patchBody(value: NgSelectHelperBody): this; /** * Sets the request body (only works with POST requests) * @param newBody New body data * @returns This instance for method chaining */ setBody(newBody: NgSelectHelperBody): this; /** * Clears the internal cache * @returns This instance for method chaining */ clearCache(): this; /** * Sets route parameters for the URL * @param newRouteParam Route parameter to append * @returns This instance for method chaining */ setRouteParam(newRouteParam: string): this; /** * Patches query parameters * @param value Query parameters to merge * @returns This instance for method chaining */ patchQueryParams(value: NgSelectHelperQueryParam): this; /** * Removes a query parameter * @param key Query parameter key to remove * @returns This instance for method chaining */ removeQueryParam(key: string): this; /** * Sets query parameters * @param newQueryParams New query parameters * @returns This instance for method chaining */ setQueryParams(newQueryParams: NgSelectHelperQueryParam): this; /** * Handler for ng-select blur event */ onBlur(): void; /** * Handler for ng-select close event */ onClose(): void; /** * Handler for ng-select clear event */ onClear(): Promise<void>; /** * Handler for ng-select open event */ onOpen(): void; /** * Handler for ng-select scroll to end event */ onScrollToEnd(): void; /** * Gets whether the last API call was successful */ get isLastApiCallSuccessful(): boolean; /** * Gets whether the limit has been reached */ get limitReached(): boolean; /** * Gets current query parameters */ get queryParams(): NgSelectHelperQueryParam; /** * Gets current request body */ get body(): NgSelectHelperBody; /** * Gets current page number */ get page(): number; /** * Gets total count of available items */ get totalCount(): number; /** * Gets whether initialization is complete */ get isInitDone(): boolean; /** * Initializes the NgSelectHelper with event handlers * Should be called in ngOnInit or similar lifecycle method */ init(): void; /** * Loads data from the API * @param page Page number * @param limit Items per page * @param searchText Search term * @returns Observable of paged data response */ private loadDataFromApi; /** * Updates page counter if conditions are met */ private runProbablePageCounterUpdate; /** * Checks if the limit has been reached */ private runLimitReachedCheck; /** * Updates state after successful initial API call * @param data Response data */ private updateStateOnSuccessfulInitialApiCall; /** * Updates state after successful subsequent API call * @param data Response data */ private updateStateOnSuccessfulSubsequentApiCall; /** * Updates state after failed API call */ private updateStateOnFailedApiCall; /** * Resets all state to initial values * @param opts Reset options */ resetAll(opts?: NgSelectHelperResetOpts): void; /** * Resets search text */ private resetSearchText; } /** * Utility function to initialize NgSelect helpers with error handling * * This function streamlines the initialization process for multiple NgSelect helpers * by automatically initializing them and setting up error handling subscriptions. * * @param helpers$ Observable of NgSelectHelper instances * @param destroyRef Angular DestroyRef for automatic cleanup * @param onAjaxError Callback function to handle