It seems to me that in almost all cases where we specify component @Input
s/@Output
s we could alternatively not have any @Input
s/@Output
s but instead use @ViewChild
to access component properties directly. For example, consider these two possible APIs for a pager:
Option 1: Expose current page and total pages as @Input
s, make event emitters (@Output
s) for the next/previous page requests.
<pager
[currentPage]="..."
[totalPages]="..."
(requestsNextPage$)="..."
(requestsPreviousPage$)="..."
></pager>
Option 2: Make simple properties for current page and total pages, make observables/subjects for next/previous page requests and expose via @ViewChild
.
<pager></pager>
@ViewChild(PagerComponent)
pager: PagerComponent
pager.currentPage = ...
pager.totalPages = ...
pager.requestsNextPage$.subscribe(...)
pager.requestsPreviousPage$.subscribe(...)
My question is, if both of these options are equally possible in most cases, what is the preferred/best practice and why?
The @ViewChild decorator allows us to inject into a component class references to elements used inside its template, that's what we should use it for. Using @ViewChild we can easily inject components, directives or plain DOM elements.
While Angular inputs/outputs should be used when sharing data to and from child components, ViewChild should be used when trying to utilize properties and methods of the child component directly in the parent component.
ViewChild makes it possible to access native DOM elements that have a template reference variable. Whale! The parent component was able to set the value of the child DOM Element.
@Input() and @Output() give a child component a way to communicate with its parent component. @Input() lets a parent component update data in the child component. Conversely, @Output() lets the child send data to a parent component.
The two situations you describe are not equivalent.
Situation A:
<child [property]="value"></child>
The child component will be rendered with "property = value" and whenever "value" changes, the child component's view will be updated (because an input property changed).
Situation B:
<child></child>
child.property = value;
The child component is rendered with "property = value" (depending when in the lifecycle this code runs) and further changes will NOT be reflected in the child component's view.
If you're just setting an initial value that never changes, then it may be possible for these two situations to be equivalent. However, that's unlikely to be what you want to do. Angular is very aggressive about re-using components, and one of the criteria it uses is the @Input properties. I have run into trouble where a component was reused instead of deleted and re-created due to this behavior, and it can be very frustrating to understand and debug.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With