Search code examples
angulartypescriptinjectangular-resolver

Angular ResolveFn - inject() must be called from an injection context


While attempting to deprecate instances of Angular's "Resolve" class implementation for the preferred functional implementation "ResolveFn", I ran into a perplexing issue. I have a simple resolver that is preparing my data. I am receiving this error but unclear on why: "inject() must be called from an injection context such as a constructor, a factory function, a field initializer, or a function used with EnvironmentInjector#runInContext."

Code that Errors

import { inject } from '@angular/core';
import { ActivatedRouteSnapshot, ResolveFn } from '@angular/router';
import { PrepareAdHocReportingService } from '@features/reporting/services/prepare-ad-hoc-reporting.service';
import { DashboardsService } from '../dashboards.service';

export const homeDashboardResolver: ResolveFn<void> = async (
    route: ActivatedRouteSnapshot
) => {
    await inject(PrepareAdHocReportingService).resolve();
    const dashboardsService = inject(DashboardsService);
    await Promise.all([
      dashboardsService.fetchWidgets(),
      dashboardsService.getDashboardDetail(route.params.id)
    ]);
};

The most confusing part is that if I simply move the dashboardsService const up ONE line, it fixes the issue.

Working Code

import { ActivatedRouteSnapshot, ResolveFn } from '@angular/router';
import { PrepareAdHocReportingService } from '@features/reporting/services/prepare-ad-hoc-reporting.service';
import { DashboardsService } from '../dashboards.service';

export const homeDashboardResolver: ResolveFn<void> = async (
    route: ActivatedRouteSnapshot
) => {
    const dashboardsService = inject(DashboardsService);
    await inject(PrepareAdHocReportingService).resolve();
    await Promise.all([
        dashboardsService.fetchWidgets(),
        dashboardsService.getDashboardDetail(route.params.id)
    ]);
};

Why does simply moving the const up solve this injection issue?

For additional context, both DashboardsService and PrepareAdHocReportingService are injected with "providedIn: 'root'".

@Injectable({ providedIn: 'root' }) export class PrepareAdHocReportingService {}

@Injectable({ providedIn: 'root' }) export class DashboardsService {}


Solution

  • Awaiting a Promise does effectively exit the injection context.

    If you want to run in an injection context, you'll have to use runInInjectorContext after the await.