diff --git a/src/core/directives/collapsible-header.ts b/src/core/directives/collapsible-header.ts
index 1d920f4ee..704595af4 100644
--- a/src/core/directives/collapsible-header.ts
+++ b/src/core/directives/collapsible-header.ts
@@ -428,19 +428,15 @@ export class CoreCollapsibleHeaderDirective implements OnInit, OnChanges, OnDest
return;
}
- // Wait loadings to finish.
- await CoreDirectivesRegistry.waitDirectivesReady(this.page, 'core-loading', CoreLoadingComponent);
+ // Make sure elements have been added to the DOM.
+ await CoreUtils.nextTick();
- // Wait tabs to be ready.
- await CoreDirectivesRegistry.waitDirectivesReady(this.page, 'core-tabs', CoreTabsComponent);
- await CoreDirectivesRegistry.waitDirectivesReady(this.page, 'core-tabs-outlet', CoreTabsOutletComponent);
-
- // Wait loadings to finish, inside tabs (if any).
- await CoreDirectivesRegistry.waitDirectivesReady(
- this.page,
- 'core-tab core-loading, ion-router-outlet core-loading',
- CoreLoadingComponent,
- );
+ // Wait all loadings and tabs to finish loading.
+ await CoreDirectivesRegistry.waitMultipleDirectivesReady(this.page, [
+ { selector: 'core-loading', class: CoreLoadingComponent },
+ { selector: 'core-tabs', class: CoreTabsComponent },
+ { selector: 'core-tabs-outlet', class: CoreTabsOutletComponent },
+ ]);
}
/**
diff --git a/src/core/features/siteplugins/components/module-index/core-siteplugins-module-index.html b/src/core/features/siteplugins/components/module-index/core-siteplugins-module-index.html
index 7eb7bd09a..b5cb3a882 100644
--- a/src/core/features/siteplugins/components/module-index/core-siteplugins-module-index.html
+++ b/src/core/features/siteplugins/components/module-index/core-siteplugins-module-index.html
@@ -6,7 +6,8 @@
-
+
this.updateCachedContent();
- this.onContentLoaded.emit({ refresh: !!refresh, success: true });
+ this.onContentLoaded.emit({ refresh: !!refresh, success: true, content: this.content });
} catch (error) {
// Make it think it's loaded - otherwise it sticks on 'loading' and stops navigation working.
this.content = '';
- this.onContentLoaded.emit({ refresh: !!refresh, success: false });
+ this.onContentLoaded.emit({ refresh: !!refresh, success: false, content: this.content });
CoreDomUtils.showErrorModalDefault(error, 'core.errorloadingcontent', true);
} finally {
@@ -282,4 +282,5 @@ export class CoreSitePluginsPluginContentComponent implements OnInit, DoCheck {
export type CoreSitePluginsPluginContentLoadedData = {
refresh: boolean;
success: boolean;
+ content: string;
};
diff --git a/src/core/singletons/directives-registry.ts b/src/core/singletons/directives-registry.ts
index a246ed822..63642e12d 100644
--- a/src/core/singletons/directives-registry.ts
+++ b/src/core/singletons/directives-registry.ts
@@ -114,15 +114,16 @@ export class CoreDirectivesRegistry {
selector?: string,
directiveClass?: DirectiveConstructor,
): Promise {
- let elements: Element[] = [];
-
- if (!selector || element.matches(selector)) {
- // Element to wait is myself.
- elements = [element];
- } else {
- elements = Array.from(element.querySelectorAll(selector));
- }
+ const findElements = (): Element[] => {
+ if (!selector || element.matches(selector)) {
+ // Element to wait is myself.
+ return [element];
+ } else {
+ return Array.from(element.querySelectorAll(selector));
+ }
+ };
+ const elements = findElements();
if (!elements.length) {
return;
}
@@ -135,6 +136,63 @@ export class CoreDirectivesRegistry {
// Wait for next tick to ensure directives are completely rendered.
await CoreUtils.nextTick();
+
+ // Check if there are new elements now that the found elements are ready (there could be nested elements).
+ if (elements.length !== findElements().length) {
+ await this.waitDirectivesReady(element, selector, directiveClass);
+ }
+ }
+
+ /**
+ * Get all directive instances (with multiple types) and wait for them to be ready.
+ *
+ * @param element Root element.
+ * @param directives Directives to wait.
+ * @returns Promise resolved when done.
+ */
+ static async waitMultipleDirectivesReady(
+ element: Element,
+ directives: DirectiveData[],
+ ): Promise {
+ const findElements = (selector?: string): Element[] => {
+ if (!selector || element.matches(selector)) {
+ // Element to wait is myself.
+ return [element];
+ } else {
+ return Array.from(element.querySelectorAll(selector));
+ }
+ };
+
+ let allElements: Element[] = [];
+
+ await Promise.all(directives.map(async directive => {
+ const elements = findElements(directive.selector);
+ if (!elements.length) {
+ return;
+ }
+
+ allElements = allElements.concat(elements);
+
+ await Promise.all(elements.map(async element => {
+ const instances = this.resolveAll(element, directive.class);
+
+ await Promise.all(instances.map(instance => instance.ready()));
+ }));
+ }));
+
+ // Wait for next tick to ensure directives are completely rendered.
+ await CoreUtils.nextTick();
+
+ // Check if there are new elements now that the found elements are ready (there could be nested elements).
+ const elementsAfterReady = directives.reduce((elements, directive) => {
+ elements = elements.concat(findElements(directive.selector));
+
+ return elements;
+ }, []);
+
+ if (allElements.length !== elementsAfterReady.length) {
+ await this.waitMultipleDirectivesReady(element, directives);
+ }
}
}
@@ -144,3 +202,11 @@ export class CoreDirectivesRegistry {
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type DirectiveConstructor = { new(...args: any[]): T };
+
+/**
+ * Data to identify a directive when waiting for ready.
+ */
+type DirectiveData = {
+ selector?: string; // If defined, CSS Selector to wait for.
+ class?: DirectiveConstructor; // Directive class.
+};