Let's say I have a component, <app-card>
that encapsulates some information into a region on-screen. I'd like to use directives to individually add functionality as needed. For example, if I'd like the card to have a checkbox, I can simply apply the CardIsCheckableDirective
to the component, like so:
<app-card [appCardIsCheckable]></app-card>
Now say I'd also like this component to be draggable and droppable, using mousedown and mouseup events, so I create a CardIsDraggableDirective
, which can also be applied to the component host:
<app-card [appCardIsCheckable] [appCardIsDraggable]></app-card>
Unfortunately, the implementation details of the checkable directive and the draggable directive conflict, because of a need to distinguish between the click event and the mousedown/mouseup events, so it's not unreasonable to imagine the checkable directive modifies its behaviour when the draggable directive is present, and vice versa.
CardIsCheckableDirective
can constructor inject CardIsDraggableDirective
like so:
public constructor(@Optional() @Host() public cardIsDraggable: CardIsDraggableDirective) {}
If the cardIsDraggable
property is not null, then the directive knows the other directive is also bound on the host component, and it can modify it's functionality. However, as soon as you perform the inverse injection, by providing CardIsCheckableDirective
to CardIsDraggableDirective
, Angular throws the following error:
NG0200: Circular dependency in DI detected for CardIsCheckableDirective. Find more at https://angular.io/errors/NG0200
This support article on Angular's website tacitly implies your architecture is incorrect by suggesting a refactoring of your service structure to break the circular dependency. However, this is two directives both simply needing knowledge of whether the opposing directive exists on the host component; which is in my view a reasonable request.
How can this circular dependency loop be broken while preserving the required functionality?