{ "id": "guide/dependency-injection-navtree", "title": "Navigate the component tree with DI", "contents": "\n\n\n
To ensure that you have the best experience possible, this topic is marked for archiving until we determine\nthat it clearly conveys the most accurate information possible.
\nIn the meantime, this topic might be helpful: Hierarchical injectors.
\nIf you think this content should not be archived, please file a GitHub issue.
\nApplication components often need to share information.\nYou can often use loosely coupled techniques for sharing information,\nsuch as data binding and service sharing,\nbut sometimes it makes sense for one component to have a direct reference to another component.\nYou need a direct reference, for instance, to access values or call methods on that component.
\nObtaining a component reference is a bit tricky in Angular.\nAngular components themselves do not have a tree that you can\ninspect or navigate programmatically. The parent-child relationship is indirect,\nestablished through the components' view objects.
\nEach component has a host view, and can have additional embedded views.\nAn embedded view in component A is the\nhost view of component B, which can in turn have embedded view.\nThis means that there is a view hierarchy for each component,\nof which that component's host view is the root.
\nThere is an API for navigating down the view hierarchy.\nCheck out Query
, QueryList
, ViewChildren
, and ContentChildren
\nin the API Reference.
There is no public API for acquiring a parent reference.\nHowever, because every component instance is added to an injector's container,\nyou can use Angular dependency injection to reach a parent component.
\nThis section describes some techniques for doing that.
\n\n\nYou use standard class injection to acquire a parent component whose type you know.
\nIn the following example, the parent AlexComponent
has several children including a CathyComponent
:
Cathy reports whether or not she has access to Alex\nafter injecting an AlexComponent
into her constructor:
Notice that even though the @Optional qualifier\nis there for safety,\nthe alex
parameter is set.
What if you don't know the concrete parent component class?
\nA re-usable component might be a child of multiple components.\nImagine a component for rendering breaking news about a financial instrument.\nFor business reasons, this news component makes frequent calls\ndirectly into its parent instrument as changing market data streams by.
\nThe app probably defines more than a dozen financial instrument components.\nIf you're lucky, they all implement the same base class\nwhose API your NewsComponent
understands.
Looking for components that implement an interface would be better.\nThat's not possible because TypeScript interfaces disappear\nfrom the transpiled JavaScript, which doesn't support interfaces.\nThere's no artifact to look for.
\nThis isn't necessarily good design.\nThis example is examining whether a component can\ninject its parent via the parent's base class.
\nThe sample's CraigComponent
explores this question. Looking back,\nyou see that the Alex
component extends (inherits) from a class named Base
.
The CraigComponent
tries to inject Base
into its alex
constructor parameter and reports if it succeeded.
Unfortunately, this doesn't work.\nThe alex
parameter is null.\nYou cannot inject a parent by its base class.
You can find a parent component with a class interface.
\nThe parent must cooperate by providing an alias to itself in the name of a class interface token.
\nRecall that Angular always adds a component instance to its own injector;\nthat's why you could inject Alex into Cathy earlier.
\nWrite an alias provider—a provide
object literal with a useExisting
\ndefinition—that creates an alternative way to inject the same component instance\nand add that provider to the providers
array of the @Component()
metadata for the AlexComponent
.
Parent is the provider's class interface token.\nThe forwardRef breaks the circular reference you just created by having the AlexComponent
refer to itself.
Carol, the third of Alex's child components, injects the parent into its parent
parameter,\nthe same way you've done it before.
Here's Alex and family in action.
\nImagine one branch of a component hierarchy: Alice -> Barry -> Carol.\nBoth Alice and Barry implement the Parent
class interface.
Barry is the problem. He needs to reach his parent, Alice, and also be a parent to Carol.\nThat means he must both inject the Parent
class interface to get Alice and\nprovide a Parent
to satisfy Carol.
Here's Barry.
\nBarry's providers
array looks just like Alex's.\nIf you're going to keep writing alias providers like this you should create a helper function.
For now, focus on Barry's constructor.
\nIt's identical to Carol's constructor except for the additional @SkipSelf
decorator.
@SkipSelf
is essential for two reasons:
It tells the injector to start its search for a Parent
dependency in a component above itself,\nwhich is what parent means.
Angular throws a cyclic dependency error if you omit the @SkipSelf
decorator.
NG0200: Circular dependency in DI detected for BethComponent. Dependency path: BethComponent -> Parent -> BethComponent
Here's Alice, Barry, and family in action.
\nYou learned earlier that a class interface is an abstract class used as an interface rather than as a base class.
\nThe example defines a Parent
class interface.
The Parent
class interface defines a name
property with a type declaration but no implementation.\nThe name
property is the only member of a parent component that a child component can call.\nSuch a narrow interface helps decouple the child component class from its parent components.
A component that could serve as a parent should implement the class interface as the AliceComponent
does.
Doing so adds clarity to the code. But it's not technically necessary.\nAlthough AlexComponent
has a name
property, as required by its Base
class,\nits class signature doesn't mention Parent
.
AlexComponent
should implement Parent
as a matter of proper style.\nIt doesn't in this example only to demonstrate that the code will compile and run without the interface.