fix(content): ensure scrollEl is always available in scroll methods (#24255)

This commit is contained in:
Amanda Smith
2021-11-24 08:40:36 -06:00
committed by GitHub
parent 55db38ddc5
commit 36a096c9b6

View File

@ -2,6 +2,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Host, List
import { getIonMode } from '../../global/ionic-global';
import { Color, ScrollBaseDetail, ScrollDetail } from '../../interface';
import { componentOnReady } from '../../utils/helpers';
import { isPlatform } from '../../utils/platform';
import { createColorClasses, hostContext } from '../../utils/theme';
@ -25,7 +26,7 @@ export class Content implements ComponentInterface {
private queued = false;
private cTop = -1;
private cBottom = -1;
private scrollEl!: HTMLElement;
private scrollEl?: HTMLElement;
private isMainContent = true;
// Detail is used in a hot loop in the scroll event, by allocating it here
@ -168,7 +169,7 @@ export class Content implements ComponentInterface {
readTask(ts => {
this.queued = false;
this.detail.event = ev;
updateScrollDetail(this.detail, this.scrollEl, ts, shouldStart);
updateScrollDetail(this.detail, this.scrollEl!, ts, shouldStart);
this.ionScroll.emit(this.detail);
});
}
@ -183,8 +184,16 @@ export class Content implements ComponentInterface {
* and `scrollToPoint()` to scroll the content into a certain point.
*/
@Method()
getScrollElement(): Promise<HTMLElement> {
return Promise.resolve(this.scrollEl);
async getScrollElement(): Promise<HTMLElement> {
/**
* If this gets called in certain early lifecycle hooks (ex: Vue onMounted),
* scrollEl won't be defined yet with the custom elements build, so wait for it to load in.
*/
if (!this.scrollEl) {
await new Promise(resolve => componentOnReady(this.el, resolve));
}
return Promise.resolve(this.scrollEl!);
}
/**
@ -203,8 +212,9 @@ export class Content implements ComponentInterface {
* @param duration The amount of time to take scrolling to the bottom. Defaults to `0`.
*/
@Method()
scrollToBottom(duration = 0): Promise<void> {
const y = this.scrollEl.scrollHeight - this.scrollEl.clientHeight;
async scrollToBottom(duration = 0): Promise<void> {
const scrollEl = await this.getScrollElement();
const y = scrollEl!.scrollHeight - scrollEl!.clientHeight;
return this.scrollToPoint(undefined, y, duration);
}
@ -216,8 +226,9 @@ export class Content implements ComponentInterface {
* @param duration The amount of time to take scrolling by that amount.
*/
@Method()
scrollByPoint(x: number, y: number, duration: number): Promise<void> {
return this.scrollToPoint(x + this.scrollEl.scrollLeft, y + this.scrollEl.scrollTop, duration);
async scrollByPoint(x: number, y: number, duration: number): Promise<void> {
const scrollEl = await this.getScrollElement();
return this.scrollToPoint(x + scrollEl!.scrollLeft, y + scrollEl!.scrollTop, duration);
}
/**
@ -229,7 +240,7 @@ export class Content implements ComponentInterface {
*/
@Method()
async scrollToPoint(x: number | undefined | null, y: number | undefined | null, duration = 0): Promise<void> {
const el = this.scrollEl;
const el = await this.getScrollElement();
if (duration < 32) {
if (y != null) {
el.scrollTop = y;