MOBILE-3833 collapsible: Wait tabs to be ready
parent
23275c7903
commit
cdeb4af6da
|
@ -23,6 +23,7 @@ import {
|
|||
AfterViewInit,
|
||||
ViewChild,
|
||||
SimpleChange,
|
||||
ElementRef,
|
||||
} from '@angular/core';
|
||||
import { IonSlides } from '@ionic/angular';
|
||||
import { BackButtonEvent } from '@ionic/core';
|
||||
|
@ -35,6 +36,9 @@ import { CoreEventObserver } from '@singletons/events';
|
|||
import { CoreDom } from '@singletons/dom';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreError } from './errors/error';
|
||||
import { CorePromisedValue } from './promised-value';
|
||||
import { AsyncComponent } from './async-component';
|
||||
import { CoreComponentsRegistry } from '@singletons/components-registry';
|
||||
|
||||
/**
|
||||
* Class to abstract some common code for tabs.
|
||||
|
@ -42,7 +46,7 @@ import { CoreError } from './errors/error';
|
|||
@Component({
|
||||
template: '',
|
||||
})
|
||||
export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, AfterViewInit, OnChanges, OnDestroy {
|
||||
export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, AfterViewInit, OnChanges, OnDestroy, AsyncComponent {
|
||||
|
||||
// Minimum tab's width.
|
||||
protected static readonly MIN_TAB_WIDTH = 107;
|
||||
|
@ -85,13 +89,16 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
|
|||
// Swiper 6 documentation: https://swiper6.vercel.app/
|
||||
protected isInTransition = false; // Wether Slides is in transition.
|
||||
protected subscriptions: Subscription[] = [];
|
||||
protected onReadyPromise = new CorePromisedValue<void>();
|
||||
|
||||
tabAction: CoreTabsRoleTab<T>;
|
||||
|
||||
constructor() {
|
||||
constructor(element: ElementRef) {
|
||||
this.backButtonFunction = this.backButtonClicked.bind(this);
|
||||
|
||||
this.tabAction = new CoreTabsRoleTab(this);
|
||||
|
||||
CoreComponentsRegistry.register(element.nativeElement, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -525,6 +532,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
|
|||
if (suceeded !== false) {
|
||||
this.tabSelected(tabToSelect, index);
|
||||
}
|
||||
this.onReadyPromise.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -554,7 +562,14 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft
|
|||
}
|
||||
|
||||
/**
|
||||
* Component destroyed.
|
||||
* @inheritdoc
|
||||
*/
|
||||
async ready(): Promise<void> {
|
||||
return await this.onReadyPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.isDestroyed = true;
|
||||
|
|
|
@ -20,7 +20,6 @@ import {
|
|||
OnDestroy,
|
||||
AfterViewInit,
|
||||
ViewChild,
|
||||
ElementRef,
|
||||
SimpleChange,
|
||||
} from '@angular/core';
|
||||
import { IonRouterOutlet, IonTabs, ViewDidEnter, ViewDidLeave } from '@ionic/angular';
|
||||
|
@ -69,12 +68,6 @@ export class CoreTabsOutletComponent extends CoreTabsBaseComponent<CoreTabsOutle
|
|||
protected lastActiveComponent?: Partial<ViewDidLeave>;
|
||||
protected existsInNavigationStack = false;
|
||||
|
||||
constructor(element: ElementRef) {
|
||||
super();
|
||||
|
||||
CoreComponentsRegistry.register(element.nativeElement, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init tab info.
|
||||
*
|
||||
|
@ -223,7 +216,7 @@ export class CoreTabsOutletComponent extends CoreTabsBaseComponent<CoreTabsOutle
|
|||
}
|
||||
|
||||
/**
|
||||
* Component destroyed.
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
super.ngOnDestroy();
|
||||
|
|
|
@ -16,6 +16,7 @@ import { Directive, ElementRef, Input, OnChanges, OnDestroy, OnInit, SimpleChang
|
|||
import { CorePromisedValue } from '@classes/promised-value';
|
||||
import { CoreLoadingComponent } from '@components/loading/loading';
|
||||
import { CoreTabsOutletComponent } from '@components/tabs-outlet/tabs-outlet';
|
||||
import { CoreTabsComponent } from '@components/tabs/tabs';
|
||||
import { CoreSettingsHelper } from '@features/settings/services/settings-helper';
|
||||
import { ScrollDetail } from '@ionic/core';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
|
@ -230,8 +231,12 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
|
|||
* Search the page content, initialize it, and wait until it's ready for the transition to trigger on scroll.
|
||||
*/
|
||||
protected async initializeContent(): Promise<void> {
|
||||
if (!this.page) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize from tabs.
|
||||
const tabs = CoreComponentsRegistry.resolve(this.page?.querySelector('core-tabs-outlet'), CoreTabsOutletComponent);
|
||||
const tabs = CoreComponentsRegistry.resolve(this.page.querySelector('core-tabs-outlet'), CoreTabsOutletComponent);
|
||||
|
||||
if (tabs) {
|
||||
const outlet = tabs.getOutlet();
|
||||
|
@ -249,7 +254,7 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
|
|||
}
|
||||
|
||||
// Initialize from page content.
|
||||
const content = this.page?.querySelector('ion-content:not(.disable-scroll-y)');
|
||||
const content = this.page.querySelector('ion-content:not(.disable-scroll-y)');
|
||||
|
||||
if (!content) {
|
||||
throw new Error('[collapsible-header] Couldn\'t get content');
|
||||
|
@ -357,7 +362,19 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
|
|||
return;
|
||||
}
|
||||
|
||||
// Wait loadings to finish.
|
||||
await CoreComponentsRegistry.waitComponentsReady(this.page, 'core-loading', CoreLoadingComponent);
|
||||
|
||||
// Wait tabs to be ready.
|
||||
await CoreComponentsRegistry.waitComponentsReady(this.page, 'core-tabs', CoreTabsComponent);
|
||||
await CoreComponentsRegistry.waitComponentsReady(this.page, 'core-tabs-outlet', CoreTabsOutletComponent);
|
||||
|
||||
// Wait loadings to finish, inside tabs (if any).
|
||||
await CoreComponentsRegistry.waitComponentsReady(
|
||||
this.page,
|
||||
'core-tab core-loading, ion-router-outlet core-loading',
|
||||
CoreLoadingComponent,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { AsyncComponent } from '@classes/async-component';
|
||||
import { CoreUtils } from '@services/utils/utils';
|
||||
import { CoreLogger } from './logger';
|
||||
|
||||
/**
|
||||
* Registry to keep track of component instances.
|
||||
|
@ -22,6 +23,7 @@ import { CoreUtils } from '@services/utils/utils';
|
|||
export class CoreComponentsRegistry {
|
||||
|
||||
private static instances: WeakMap<Element, unknown> = new WeakMap();
|
||||
protected static logger = CoreLogger.getInstance('CoreComponentsRegistry');
|
||||
|
||||
/**
|
||||
* Register a component instance.
|
||||
|
@ -78,6 +80,8 @@ export class CoreComponentsRegistry {
|
|||
): Promise<void> {
|
||||
const instance = this.resolve(element, componentClass);
|
||||
if (!instance) {
|
||||
this.logger.error('No instance registered for element ' + componentClass, element);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -97,15 +101,21 @@ export class CoreComponentsRegistry {
|
|||
selector: string,
|
||||
componentClass?: ComponentConstructor<T>,
|
||||
): Promise<void> {
|
||||
let elements: Element[] = [];
|
||||
|
||||
if (element.matches(selector)) {
|
||||
// Element to wait is myself.
|
||||
await CoreComponentsRegistry.waitComponentReady<T>(element, componentClass);
|
||||
elements = [element];
|
||||
} else {
|
||||
await Promise.all(Array
|
||||
.from(element.querySelectorAll(selector))
|
||||
.map(element => CoreComponentsRegistry.waitComponentReady<T>(element, componentClass)));
|
||||
elements = Array.from(element.querySelectorAll(selector));
|
||||
}
|
||||
|
||||
if (!elements.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Promise.all(elements.map(element => CoreComponentsRegistry.waitComponentReady<T>(element, componentClass)));
|
||||
|
||||
// Wait for next tick to ensure components are completely rendered.
|
||||
await CoreUtils.nextTick();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue