Here's my scenario:
I have a component, configured with the OnPush strategy, that displays a PDF document, page by page, and allows the user to scroll through pages and navigate to a certain page. It also exposes an input property scrollToPage
which allows the parent to navigate to a certain page.
@Component({
selector: 'pdf-document',
templateUrl: './pdf-document.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PdfDocumentComponent implements OnChanges {
@Input() scrollToPage: number;
ngOnChanges(changes: SimpleChanges) {
if (changes.scrollToPage) {
this.goToPage(this.scrollToPage);
}
}
public goToPage(page: number) {
...
}
}
All works as expected, except for one scenario:
- Parent sets the
scrollToPage
input to, let's say, number 2 - The ngOnChanges triggers and scrolls to page 2
- The user navigates to another page inside the PdfDocumentComponent (the goToPage function is called from the view)
- The parent sets again the
scrollToPage
input to number 2
In this case, the ngOnChanges
is not triggered and the goToPage
function is not called, because the previous value of scrollToPage
is the same, number 2.
To fix this problem I can only see 3 options, but none of them seem appropriate and are more or less hacks:
- Change the input type to be an object and always send a new reference. (I don't like this because it doesn't make sense to send an object when I really want it to send a simple number)
- Use
@ViewChild
in the parent to get a reference to the child component and call from there thegoToPage
function. (I don't like this because I want to keep my component's contract with the outside as clear as possible - using only @input and @output properties. Otherwise, I have to document these public functions too.) - Change the OnPush strategy to Default. (This is actually not an option for me)
Do you guys know any other solutions to this problem? Is there a more elegant way of solving it?