Search code examples
angulardependency-injectionmodulelazy-loadingguard

Affect of Angular Guard within lazy loaded feature module with service providedIn: 'root'


Ok, let's imagine I have AppRoutingModule where I declare routes with lazy loading modules, then I need for at least one route to use a guard for example CanDeactivate. This guard is placed in one of the feature modules and it uses service for validation, which is in the same module.

So when I run the code, I obviously got nullInjectorError: R3InjectorError(AppModule)[guard-> service-> service-> service], so I decided to use providedIn: 'root' in the @Injectable in that service, which solved my problem, but I'm not sure is that somehow affect lazy loading ?

So the question is: Does providedIn: 'root' affect lazy loading. Will it remain "lazy" loading or it will load immediately ?

Edit:

Route inside AppRouting looks like:

{
    path: PATHS.appointmentsCall,
    canDeactivate: [InterruptGuard],
    loadChildren: () => import('some path').then((m) => m.CallModule),
},

Guard in the CallModule looks like this:

@Injectable({
    providedIn: 'root',
})
export class InterruptGuard implements CanDeactivate<unknown> {
    constructor(private readonly facade: CallFacade) {}
    ...
}

CallFacade be like:

 @Injectable({
        providedIn: 'root',
    })
    export class CallFacade { 
        ... 
    }

Solution

  • All eagerly loaded modules share their RootInjector(AppModule in simple terms). When you provide a service using @Injectable annotation together with providedIn: 'root' is like you added it to AppModule providers array. One instance of that service will be available throughout application.

    Adding @Injectable({ providedIn: 'root' }) to your service won't mess your lazily loaded module. If the service is only used within a lazy loaded module it will be lazy loaded with that module, otherwise it will be provided as soon application is bootstraped. That service is provided in RootInjector.

    It is logical that in this case it won't throw an NullInjector error, which is the last stop where Angular tries to resolve a dependency and there eventually throws an error.

    Additional info: when you use @Injectable({ providedIn: 'root' }) services are tree shakeable and this is the best practice in general since it reduces bundle size of an application.

    Per https://juristr.com/blog/2021/04/angular-di-and-lazy-modules/ enter image description here