Consider the following situation: A parent component uses a child component in its template, and the child component has a reference to the parent component injected into it.
parent.component.html:
<child></child>
child.component.ts:
import { ParentComponent } from '../parent/parent.component.ts'
@Component({
selector: 'child'
...
})
export class ChildComponent {
constructor(private parent: ParentComponent) { }
}
When using this setup in a library that is compiled with the recommended partial compilation mode, the compiler throws the NG3003 error. The Angular documentation provides the following ideas to fix the issue:
Try to re-arrange your dependencies to avoid the cycle. For example using an intermediate interface that is stored in an independent file that can be imported to both dependent files without causing an import cycle.
Move the classes that reference each other into the same file, to avoid any imports between them.
Convert import statements to type-only imports (using import type syntax) if the imported declarations are only used as types, as type-only imports do not contribute to cycles.
Is there another way to solve the N3003 error without moving the parent and child components into the same file?
The N3003 error in the described situation can be solved with the use of an InjectionToken as follows:
Create an injection token:
parent.token.ts:
export const PARENT = new InjectionToken('Parent Component');
Assign the parent component to the injection token:
parent.component.ts
import { ParentComponent } from '../parent/parent.component.ts'
@Component({
...
provider:[{
provide: PARENT,
useExisting: ParentComponent
}]
})
export class ParentComponent { }
In the child component, ask the injector to inject the injection token, and reference the parent component by type only:
child.component.ts
// Import ParentComponent as a type only.
import type { ParentComponent } from '../parent/parent.component.ts';
import { PARENT } from '../parent/parent.token.ts';
@Component({ ... })
export class ChildComponent {
constructor(@Inject(PARENT) private parent: ParentComponent) { }
}