Can't resolve all parameters - Angular 8

Posted on November 27, 2019

What follows is an explanation of how to resolve an issue that you may hit with Angular if you are using services from modules. In my application I use the pattern of having a service that can be used to display modals, so that other components can show a modal using a method call, and not have to worry about the specifics of the modal implementation.

As a mock example, suppose you have a feature module, that has a component, a modal, and a modal service:

@NgModule({
    imports: [
        CommonModule,
        ...
    ],
    declarations: [SpecialList, SpecialModal],
    providers: [SpecialModalService],
    exports: [SpecialList]
})
export class SpecialFeatureModule {

}

Now suppose the SpecialList component, which shows a list of special items, and allows you to click on them and have the SpecialModal displayed, It might have a constructor like:

export class SpecialList {
    constructor(
        private specialModalService: SpecialModalService,
        private anotherService: NotSoSpecialService
    ) {}

This would cause an error such as Can't resolve all parameters for SpecialList: (?, [object Object]).

My reading of the issue is that, because both the SpecialModalService and the SpecialList are both from the same module, they each get instanciated effectively at the same time, so they aren’t available for injecting.

To overcome this we can use a forwardRef, which will be resolved later, allowing the module to be setup, and for objects within it to get references to each other.

export class SpecialList {
    constructor(
        @Inject(forwardRef(() => SpecialModalService)) private specialModalService: SpecialModalService,
        private anotherService: NotSoSpecialService
    ) {}

Conclusion

This approach logically hangs together for me, however, it seems odd that this would be an issue given the number of situations where it would make sense to have references to other objects within a module. I wouldn’t be surprised if there was a different way to declare the service, or inject it, that resolves this more cleanly.

I’ll update this post if a better explanation becomes apparent.