tldr;
Sometimes we need to interact with a child component from a parent component, but it’s not viable to do so through Inputs. ViewChild allows you to gain access to the child component and call methods from its public API as needed.
Background
I was recently working on a project where I needed to use our custom AccordionComponent. The toggle to show and hide the body content of the accordion is contained within the component. The design, though, needed me to move the toggle to a different location. This wasn’t possible to do in the component, as there are too many edge cases for where you might want to put the trigger. I wanted to find a way that would give me the flexibility to put the trigger anywhere I needed, as well as the simplicity of having it provided when needed as well.
What is ViewChild?
There is a decorator in Angular called ViewChild which gives you access in the component’s TypeScript class to a piece of the template. It will look for the first element in the template that matches the selector, and if the view is updated the reference will update as well.
There are a few ways to select the item you need on the page. The first is via a template variable. Let’s say you have the following HTML:
<button #myBtn></button>
In this case, we have a button element with the template variable #myBtn. If we needed access to this in the TypeScript file, we could do that with the following code:
@ViewChild(‘myBtn’) myButton: ElementRef;
After gaining access to the button, we could interact with it as needed in the TypeScript file.
Another way to select something is by adding a service in the parentheses of the ViewChild decorator. If you use a service there, it will select the service in the child component tree. I’ve never used it in this way, but if your child component had a singleton service and the parent needed access to it for some reason, this would help you get access to that service.
The last way that I’ll cover to use the selector is by adding a component or directive class name inside the parentheses:
@ViewChild(AccordionComponent) accordion: AccordionComponent;
In this case, Angular will find the first instance of the AccordionComponent and put that reference inside the accordion variable.
Using ViewChild in the Parent Component
Back to my situation that I described above. I needed to use the accordion component, but wanted a custom trigger. The component uses content projection, so I could provide the trigger easily, I just needed to hook up its click handler to the AccordionComponent so that it opened and closed as desired. Here’s the HTML:
<app-accordion>
<ng-container accordion-header>
<div class=”flex justify-between”>
<p>Accordion Header Title</p>
<button (click)=”handleAccordionTriggerClick()”>Accordion Trigger</button>
</div>
</ng-container>
<ng-container accordion-body>
<!– Accordion Body –>
</ng-container>
</app-accordion>
All I’ve done is added the accordion to the template of my component. Now, getting access to the accordion so I can open it is done like this:
export class ParentComponent {
@ViewChild(AccordionComponent) accordion!: AccordionComponent;
public toggleCollapsedStatus() {
this.accordion.toggleCollapsedStatus();
}
}
With this method, the AccordionComponent still manages the state of the accordion, and I can decide where the trigger is located and what it looks like. It’s the best of both worlds as far as flexibility and component isolation goes.
Conclusion
If you need to interact with the public API of a child component, ViewChild is your answer. It allows you to interact with the child component without only using Inputs. Combined with content projection, I’ve been able to make my AccordionComponent as reusable as possible.
ViewChild: Calling the Public API of a Child Component was originally published in ngconf on Medium, where people are continuing the conversation by highlighting and responding to this story.