I am creating a blog page, that fetches an article. I am using SSR/SSG.
I have problems using input signals and the new httpResource
. Neither response1
nor its alternative response2
work.
export class ArticlePageComponent {
slug = input.required<string>();
response1 = httpResource<BlogPostWrapper>(
() => 'https://foo/' + this.slug(),
); // NG0950: Input is required but no value is available yet
response2 = computed(() =>
httpResource<BlogPostWrapper>(
() =>
'https://foo/' + this.slug(),
),
); // httpResourceRef() can only be used within an injection context such as a constructor, a factory function, a field initializer, or a function used with `runInInjectionContext`.
}
After setting up the scenario for SSR, I was able to replicate the error.
The reason for the error is because you are showing the component through routing (E.g: /slug/:id
) and we receive the slug
as an input.required
.
When we render the component through routing there is no way to set the id field during normal routing configuration.
To achieve this, we must have withComponentInputBinding
so that the input.required
can read the value through the routing params. So we can add this to the app.config.ts
:
import { provideRouter, withComponentInputBinding } from '@angular/router';
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideClientHydration(withEventReplay()),
provideHttpClient(),
provideRouter(routes, withComponentInputBinding()),
],
};
After this, we are guaranteed to access the input.required
signal, so this error will go away. We can just use the original method of defining the http resource and it will work fine.
@Component({ ... })
export class SlugComponent {
private injector = inject(Injector);
slug = input.required<any>({
alias: 'id',
});
response: HttpResourceRef<any> = httpResource<any>(
() => 'https://jsonplaceholder.typicode.com/todos/' + this.slug(),
{
injector: this.injector,
}
);
}
cd test
-> npm i
-> npm run start
.Define the httpResource on the ngOnInit
hook.
You can also try defining this on the constructor
where injection context is inherently available (might not work)
Since in ngOnInit
the injection context is not inherently available, we need to provide it explicitly through the second parameter of httpResource HttpResourceOptions.
A required input was accessed but no value was bound.
This can happen when a required input is accessed too early in your directive or component. This is commonly happening when the input is read as part of class construction.
Inputs are guaranteed to be available in the ngOnInit lifecycle hook and afterwards.
export class ArticlePageComponent {
private injector = inject(Injector);
slug = input.required<BlogPostWrapper>();
response!: HttpResourceRef<any>;
ngOnInit() {
this.response = httpResource<BlogPostWrapper>(
() => 'https://foo/' + this.slug(),
{ injector: this.injector }
);
}