I tried to initialize my signal through button click, but I am getting the error:
ERROR RuntimeError: NG0203: rxResource() can only be used within an injection context such as a constructor, a factory function, a field initializer, or a function used with runInInjectionContext. Find more at https://angular.dev/errors/NG0203at assertInInjectionContext (core.mjs:2479:11)at rxResource (rxjs-interop.mjs:326:21)at _App.getUsers (main.ts:36:21)at App_Template_button_click_1_listener (main.ts:25:22)at executeListenerWithErrorHandling (core.mjs:29249:12)at wrapListenerIn_markDirtyAndPreventDefault (core.mjs:29281:18)at HTMLButtonElement. (platform-browser.mjs:806:112)at _ZoneDelegate.invokeTask (zone.js:402:33)at core.mjs:6164:49at AsyncStackTaggingZoneSpec.onInvokeTask (core.mjs:6164:30)
Below is the minimal reproducible code:
@if(rxResource) {
@if(![rs.Loading, rs.Reloading].includes(rxResource.status())) {
{{rxResource.value() | json}}
} @else{
Loading...
}
}
@if(resource) {
@if(![rs.Loading, rs.Reloading].includes(resource.status())) {
{{resource.value() | json}}
} @else{
Loading...
}
}
<button (click)="getUsers()">Get Users</button>
<button (click)="reset()">Reset</button>
rs = ResourceStatus;
http = inject(HttpClient);
resource!: ResourceRef<any>;
rxResource!: ResourceRef<any>;
getUsers() {
this.rxResource = rxResource({
loader: () => {
return this.http
.get(`https://jsonplaceholder.typicode.com/todos`)
.pipe(map((data: any) => data.slice(0, 10)));
},
});
this.resource = resource({
loader: () => {
return fetch(`https://jsonplaceholder.typicode.com/todos/`)
.then((res: any) => res.json())
.then((res: any) => {
return res.slice(0, 10);
});
},
});
}
All you need to do is the provide the Injector
DI element to the resource
or rxResource
and it will work fine.
You need to provide Injector
in all places, except the below scenarios:
Because the injector is available inside and the resource
API can access it directly.
export class App {
...
injector = inject(Injector); // <- getting injector from DI!
getUsers() {
this.rxResource = rxResource({
loader: () => {
return this.http
.get(`https://jsonplaceholder.typicode.com/todos`)
.pipe(map((data: any) => data.slice(0, 10)));
},
injector: this.injector, // <- provide injector here!
});
this.resource = resource({
loader: ({ abortSignal }) => {
return fetch(`https://jsonplaceholder.typicode.com/todos/`, {
signal: abortSignal,
})
.then((res: any) => res.json())
.then((res: any) => {
return res.slice(0, 10);
});
},
injector: this.injector, // <- provide injector here!
});
}
import {
Component,
inject,
ResourceRef,
ResourceStatus,
Injector,
resource,
} from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { rxResource } from '@angular/core/rxjs-interop';
import { HttpClient, provideHttpClient } from '@angular/common/http';
import { CommonModule } from '@angular/common';
import { map } from 'rxjs';
@Component({
selector: 'app-root',
imports: [CommonModule],
template: `
<div>
@if(rxResource) {
@if(![rs.Loading, rs.Reloading].includes(rxResource.status())) {
{{rxResource.value() | json}}
} @else{
Loading...
}
}
</div>
<hr/>
<div>
@if(resource) {
@if(![rs.Loading, rs.Reloading].includes(resource.status())) {
{{resource.value() | json}}
} @else{
Loading...
}
}
</div>
<hr/>
<div>
<button (click)="getUsers()">Get Users</button>
<button (click)="reset()">Reset</button>
</div>
`,
})
export class App {
rs = ResourceStatus;
http = inject(HttpClient);
resource!: ResourceRef<any>;
rxResource!: ResourceRef<any>;
injector = inject(Injector);
getUsers() {
this.rxResource = rxResource({
loader: () => {
return this.http
.get(`https://jsonplaceholder.typicode.com/todos`)
.pipe(map((data: any) => data.slice(0, 10)));
},
injector: this.injector,
});
this.resource = resource({
loader: ({ abortSignal }) => {
return fetch(`https://jsonplaceholder.typicode.com/todos/`, {
signal: abortSignal,
})
.then((res: any) => res.json())
.then((res: any) => {
return res.slice(0, 10);
});
},
injector: this.injector,
});
}
reset() {
if (this.resource) {
this.resource.destroy();
}
if (this.rxResource) {
this.rxResource.destroy();
}
}
}
bootstrapApplication(App, {
providers: [provideHttpClient()],
});