Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed last year.
Improve this question
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 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.
When you are using @Input(), for every change the ngOnChanges() will be called which may causes more noise.
Using ViewChild() Property decorator that configures a view query. The change detector looks for the first element or the directive matching the selector in the view DOM. If the view DOM changes, and a new child matches the selector, the property is updated.
So ViewChild() will not create such noise and is the prefer way over @Input()