angulartypescriptsignalsangular-resourceangular-signals

Creating a reusable loader for angular v19 resource API with 2 request parameters of different types


Below is the code that creates an angular19 reusable resource loader and its usage with a single request parameter:

import { ResourceLoaderParams } from "@angular/core";

function todoLoader({ request: todoId, abortSignal }: ResourceLoaderParams<number>): Promise<Todo> {
    return fetch(
      `https://jsonplaceholder.typicode.com/todos/${todoId}`, 
      { signal: abortSignal } 
    ).then((res) => res.json() as Promise<Todo>);
}

todoResource = resource({ request: this.todoId, loader: todoLoader });

My difficulty is that I cannot find a way to have two (2) request parameters. I would like to add a second parameter 'appName' of type 'string' to the request parameter.

Appreciate your help


Solution

  • We can define a type for request params, then we can convert the function to return a loader function, which will process the params.

    Also we can pass an object to the resource API and pass to the API.

    Full Code:

    import {
      Component,
      resource,
      ResourceLoader,
      ResourceLoaderParams,
      signal,
    } from '@angular/core';
    import { bootstrapApplication } from '@angular/platform-browser';
    export interface TodoLoaderRequest {
      todoId: number;
      appName: string;
    }
    export interface Todo {
      id: number;
    }
    function todoLoader(): ResourceLoader<Todo, TodoLoaderRequest> {
      return ({
        request: { todoId, appName },
        abortSignal,
      }: ResourceLoaderParams<TodoLoaderRequest>) =>
        fetch(
          `https://jsonplaceholder.typicode.com/todos/${todoId}?appName=${appName}`,
          { signal: abortSignal }
        ).then((res) => res.json() as PromiseLike<Todo>);
    }
    
    @Component({
      selector: 'app-root',
      template: `
            <a target="_blank" href="https://angular.dev/overview">
              Learn more about Angular
            </a>
          `,
    })
    export class App {
      todoId = signal(1);
      appName = signal('test');
      todoResource = resource<Todo, TodoLoaderRequest>({
        request: () => ({
          todoId: this.todoId(),
          appName: this.appName(),
        }),
        loader: todoLoader(),
      });
    }
    
    bootstrapApplication(App);
    

    Stackblitz Demo