Reputation: 1945
I'm trying to test scrollIntoView() in angular 6 and got this error --> TypeError: Cannot read property 'scrollIntoView' of null
spec:
beforeEach(() => {
fixture = TestBed.createComponent(BusinessInfoComponent);
component = fixture.componentInstance;
component.ngOnInit();
spyOn(document.getElementById('info-banner'), 'scrollIntoView').and.callThrough();
expect(document.getElementById('info-banner').scrollIntoView).toHaveBeenCalled();
expect(document.getElementById('info-banner')).not.toBeDefined();
fixture.detectChanges();
});
ts:
ngOnInit() {
document.getElementById('info-banner').scrollIntoView();
}
Upvotes: 2
Views: 8400
Reputation: 798
I tried all the previous answers but none worked for me. I came up with a workaround:
⚠️⚠️ WARNING ⚠️⚠️: this code is not recommended for enterprise applications. The problem is that it will not always take less than 50ms for myTarget from @ViewChild to become defined, thus the scrolling might not take place 100% of the time. However as for performance it is not a big problem I think.
That being said, this worked for me in 100% of the cases in my app so far so it is a good workaround for small hobby/school/university projects. In my app the wait always took less than 3ms. You can comment-in the commented-out line in your app to see how long it would take for your component.
async ngAfterViewInit() {
let timesThat1MSWasWaited = 0;
while (this.myTarget === undefined) {
await new Promise(r => setTimeout(r, 1));
if (timesThat1MSWasWaited > 50) {
console.error('FatalException: Waited too long for highlighted song to appear in DOM.');
return;
}
timesThat1MSWasWaited++;
}
// console.debug('Needed to wait at least ' + timesThat1MSWasWaited + 'ms for myTarget to appear.');
this.myTarget.nativeElement.scrollIntoView({
behavior: 'smooth',
block: 'center',
});
}
}
Upvotes: 1
Reputation: 1635
Try using this.
// Get the reference of the variable
@ViewChild("myDiv") divView: ElementRef;
this.divView.nativeElement.scrollIntoView();
<div id="info-banner" #myDiv >Info </div>
Look into this link
https://www.techiediaries.com/angular-elementref/
For accessing outside elements check this
Access DOM element outside of Angular root component
Upvotes: -1
Reputation: 723
document.getElementById('info-banner').scrollIntoView();
should go into ngAfterViewInit()
lifecycle hook.
Basically any DOM referencing should go into that hook. When ngOnInit()
is executed, DOM doesn't exist yet and therefore the error.
Upvotes: 2
Reputation: 913
Try:
Spec:
beforeEach(() => {
fixture = TestBed.createComponent(BusinessInfoComponent);
component = fixture.componentInstance;
component.ngOnInit();
spyOn(window.document.getElementById('info-banner'), 'scrollIntoView').and.callThrough();
expect(window.document.getElementById('info-banner').scrollIntoView).toHaveBeenCalled();
expect(window.document.getElementById('info-banner')).not.toBeDefined();
fixture.detectChanges();
});
Angular class
ngOnInit() {
window.document.getElementById('info-banner').scrollIntoView();
}
Upvotes: 0