import { Injector } from '@angular/core'; import { DefaultError, InfiniteData, QueryKey } from '@tanstack/query-core'; import { CreateInfiniteQueryOptions, CreateInfiniteQueryResult, DefinedCreateInfiniteQueryResult } from './types.js'; import { DefinedInitialDataInfiniteOptions, UndefinedInitialDataInfiniteOptions } from './infinite-query-options.js'; export interface InjectInfiniteQueryOptions { /** * The `Injector` in which to create the infinite query. * * If this is not provided, the current injection context will be used instead (via `inject`). */ injector?: Injector; } /** * The options for `injectInfiniteQuery` are identical to `injectQuery`, with the addition of * `initialPageParam`, `getNextPageParam`, `getPreviousPageParam`, and `maxPages`. Infinite queries can * additively "load more" data onto an existing set of data, or "infinite scroll". * * This overload is selected when `initialData` is set on the options returned by `injectInfiniteQueryFn`, * so the resulting `data` signal is never `undefined` (unless a `select` changes `TData` to include `undefined`). * * @remarks Keep in mind that imperative fetch calls, such as `fetchNextPage`, may interfere with the default * refetch behavior, resulting in outdated data. Make sure to call these functions only in response to user * actions, or add conditions like `hasNextPage() && !isFetching()`. * @see {@link infiniteQueryOptions} to share these options between `injectInfiniteQuery` and imperative APIs * like `queryClient.fetchInfiniteQuery`. * @param injectInfiniteQueryFn - A function returning the {@link DefinedInitialDataInfiniteOptions} to use — * everything you can pass to `injectInfiniteQuery`, with `initialData` set. Similar to `computed` from * Angular, this function runs in the reactive context, so signals read inside it drive the query. * @param options - Additional configuration. * @returns The same signals as `injectQuery`, with the addition of `fetchNextPage`, `fetchPreviousPage`, * `hasNextPage`, `hasPreviousPage`, `isFetchingNextPage`, and `isFetchingPreviousPage`. `data().pages` and * `data().pageParams` are also added, as long as a `select` doesn't change `TData` away from its default * `InfiniteData` shape. * * @example * ```angular-ts * @Component({ * selector: 'projects', * template: ` * * * `, * }) * export class Projects { * readonly projectsQuery = injectInfiniteQuery(() => ({ * queryKey: ['projects'], * queryFn: ({ pageParam }) => fetchProjects(pageParam), * initialPageParam: 0, * getNextPageParam: (lastPage) => lastPage.nextId, * initialData: { pages: [], pageParams: [] }, * })) * } * ``` */ export declare function injectInfiniteQuery, TQueryKey extends QueryKey = QueryKey, TPageParam = unknown>(injectInfiniteQueryFn: () => DefinedInitialDataInfiniteOptions, options?: InjectInfiniteQueryOptions): DefinedCreateInfiniteQueryResult; /** * Injects an infinite query: a declarative dependency on an asynchronous source of data that is tied to a * unique key. Infinite queries can additively "load more" data onto an existing set of data, or * "infinite scroll". * * @remarks Keep in mind that imperative fetch calls, such as `fetchNextPage`, may interfere with the default * refetch behavior, resulting in outdated data. Make sure to call these functions only in response to user * actions, or add conditions like `hasNextPage() && !isFetching()`. This is the only overload that accepts * `queryFn: skipToken`, shown below. * @see {@link infiniteQueryOptions} to share these options between `injectInfiniteQuery` and imperative APIs * like `queryClient.fetchInfiniteQuery`. * @param injectInfiniteQueryFn - A function returning the {@link UndefinedInitialDataInfiniteOptions} to use * — everything you can pass to `injectInfiniteQuery`. Similar to `computed` from Angular, this function runs * in the reactive context, so signals read inside it drive the query. * @param options - Additional configuration. * @returns The same signals as `injectQuery`, with the addition of `fetchNextPage`, `fetchPreviousPage`, * `hasNextPage`, `hasPreviousPage`, `isFetchingNextPage`, and `isFetchingPreviousPage`. `data().pages` and * `data().pageParams` are also added, as long as a `select` doesn't change `TData` away from its default * `InfiniteData` shape. * * @example * Fetching the next page from a button click: * ```angular-ts * @Component({ * selector: 'projects-list', * template: ` *
    * @for (page of projectsQuery.data()?.pages; track $index) { * @for (project of page.projects; track project.id) { *
  • {{ project.name }}
  • * } * } *
* * `, * }) * export class ProjectsList { * readonly projectsQuery = injectInfiniteQuery(() => ({ * queryKey: ['projects'], * queryFn: ({ pageParam }) => fetchProjects(pageParam), * initialPageParam: 0, * getNextPageParam: (lastPage) => lastPage.nextId, * })) * } * ``` * * @example * Fetching the next page automatically as the user scrolls, using an `IntersectionObserver` on a sentinel * element after the list: * ```angular-ts * @Component({ * selector: 'projects-list', * template: ` *
    * @for (page of projectsQuery.data()?.pages; track $index) { * @for (project of page.projects; track project.id) { *
  • {{ project.name }}
  • * } * } *
*
{{ projectsQuery.isFetchingNextPage() ? 'Loading more...' : '' }}
* `, * }) * export class ProjectsList { * readonly sentinel = viewChild>('sentinel') * * readonly projectsQuery = injectInfiniteQuery(() => ({ * queryKey: ['projects'], * queryFn: ({ pageParam }) => fetchProjects(pageParam), * initialPageParam: 0, * getNextPageParam: (lastPage) => lastPage.nextId, * })) * * constructor() { * effect((onCleanup) => { * const sentinel = this.sentinel()?.nativeElement * if ( * sentinel == null || * !this.projectsQuery.hasNextPage() || * this.projectsQuery.isFetching() * ) { * return * } * * const observer = new IntersectionObserver(([entry]) => { * if (entry?.isIntersecting) this.projectsQuery.fetchNextPage() * }) * observer.observe(sentinel) * * onCleanup(() => observer.disconnect()) * }) * } * } * ``` * * @example * A query that's disabled, type safe, until `postId` is set — pass `skipToken` as `queryFn` instead of * setting `enabled: false`: * ```angular-ts * @Component({ * selector: 'comments', * template: ` * @if (postId() == null) { * Select a post * } @else if (commentsQuery.isPending()) { * Loading... * } @else if (commentsQuery.isError()) { * Error: {{ commentsQuery.error()?.message }} * } @else { *
    * @for (page of commentsQuery.data().pages; track $index) { * @for (comment of page.comments; track comment.id) { *
  • {{ comment.text }}
  • * } * } *
* } * `, * }) * export class Comments { * readonly postId = signal(undefined) * * readonly commentsQuery = injectInfiniteQuery(() => ({ * queryKey: ['post', this.postId(), 'comments'], * queryFn: * this.postId() != null * ? ({ pageParam }) => fetchComments(this.postId()!, pageParam) * : skipToken, * initialPageParam: 0, * getNextPageParam: (lastPage) => lastPage.nextId, * })) * } * ``` */ export declare function injectInfiniteQuery, TQueryKey extends QueryKey = QueryKey, TPageParam = unknown>(injectInfiniteQueryFn: () => UndefinedInitialDataInfiniteOptions, options?: InjectInfiniteQueryOptions): CreateInfiniteQueryResult; /** * This overload accepts the general {@link CreateInfiniteQueryOptions} shape rather than the * `initialData`-aware overloads above, so whether `data` is defined can't be inferred from the call site — * useful when wrapping `injectInfiniteQuery` in your own helper function that forwards caller-provided * options. * * @param injectInfiniteQueryFn - A function that returns infinite query options. Similar to `computed` from * Angular, this function runs in the reactive context, so signals read inside it drive the query. * @param options - Additional configuration. * @returns The infinite query result. */ export declare function injectInfiniteQuery, TQueryKey extends QueryKey = QueryKey, TPageParam = unknown>(injectInfiniteQueryFn: () => CreateInfiniteQueryOptions, options?: InjectInfiniteQueryOptions): CreateInfiniteQueryResult;