Search code examples
angulartypescriptsignalsangular-resourceangular-signals

How do I start/stop the angular resource and rxResource API which is declared at the initialization of a class or service


My base requirement is to start and stop the Resource API at will. By start/stop I mean to start/stop listening for signal changes (signals provided within the request callback).

By start I mean, the resource API is supposed to act normally, eagerly load the request based on the input signal and react to signal changes.

By stop I mean, do not have any value and remain idle, even when there are new signal changes from the request signals.

Below is my minimal reproducible code along with a working stackblitz for debugging:

HTML:

<div>
  <div>
    Resource Request triggers:
  </div>
  <div>
    <input [(ngModel)]="id" type="number"/>
  </div>
</div>
<div>
  @if(![rs.Loading, rs.Reloading].includes(rxResource.status())) {
    {{rxResource.value() | json}}
  } @else{
    Loading...
  }
</div>
<hr/>
<div>
  @if(![rs.Loading, rs.Reloading].includes(resource.status())) {
    {{resource.value() | json}}
  } @else{
    Loading...
  }
</div>
<hr/>
<div>
<button (click)="start()">Start Listening</button>
<button (click)="stop()">Stop Listening</button>
</div>

TS:

  export class App {
    id = signal(1);
    rs = ResourceStatus;
    http = inject(HttpClient);
    resourceRequest = (): ResourceRequest => {
      return {
        id: this.id(),
      };
    };
    resource: ResourceRef<any> = resource<ResourceRequest, any>({
      request: this.resourceRequest,
      loader: ({ request: { id }, abortSignal }) => {
        return fetch(`https://jsonplaceholder.typicode.com/todos/${id}`, {
          signal: abortSignal,
        }).then((res: any) => res.json());
      },
    });
    rxResource: ResourceRef<any> = rxResource<ResourceRequest, any>({
      request: this.resourceRequest,
      loader: ({ request: { id } }) => {
        return this.http.get<any>(
          `https://jsonplaceholder.typicode.com/todos/${id}`
        );
      },
    });

    start() {
      // how to start the resource API programmatically.
    }

    stop() {
      // how to stop the resource API programmatically.
    }

Stackblitz Demo


Solution

  • It's not about stop/starting a resource, it's about having a having a state that represents the parameters of a loader that should pull the async data.

    If resource were meant to be enabled/disabled they would have dedicated methods for that.

    Either you have all your request parameters and you can return them.

    request: () => {
      if(myState().param1 && myState().param2) {
         return { param1: myState().param1, param2: myState.param2 }
      }
      return undefined // I don't have all my params 
    }
    

    or you don't and you return undefined, telling the resource that you don't have the necessary data to perform the async request.