MOBILE-3833 tabs: Fix tab size calculations
This commit is contained in:
		
							parent
							
								
									f56cfa3ab6
								
							
						
					
					
						commit
						b2246a01c5
					
				| @ -22,7 +22,6 @@ import { | ||||
|     OnDestroy, | ||||
|     AfterViewInit, | ||||
|     ViewChild, | ||||
|     ElementRef, | ||||
|     SimpleChange, | ||||
| } from '@angular/core'; | ||||
| import { IonSlides } from '@ionic/angular'; | ||||
| @ -34,6 +33,8 @@ import { CoreSettingsHelper } from '@features/settings/services/settings-helper' | ||||
| import { CoreAriaRoleTab, CoreAriaRoleTabFindable } from './aria-role-tab'; | ||||
| import { CoreEventObserver } from '@singletons/events'; | ||||
| import { CoreDom } from '@singletons/dom'; | ||||
| import { CoreUtils } from '@services/utils/utils'; | ||||
| import { CoreError } from './errors/error'; | ||||
| 
 | ||||
| /** | ||||
|  * Class to abstract some common code for tabs. | ||||
| @ -54,6 +55,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | ||||
| 
 | ||||
|     tabs: T[] = []; // List of tabs.
 | ||||
| 
 | ||||
|     hideTabs = false; | ||||
|     selected?: string; // Selected tab id.
 | ||||
|     showPrevButton = false; | ||||
|     showNextButton = false; | ||||
| @ -65,10 +67,11 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | ||||
|         initialSlide: 0, | ||||
|         slidesPerView: 3, | ||||
|         centerInsufficientSlides: true, | ||||
|         threshold: 10, | ||||
|     }; | ||||
| 
 | ||||
|     protected slidesElement?: HTMLIonSlidesElement; | ||||
|     protected initialized = false; | ||||
|     protected afterViewInitTriggered = false; | ||||
| 
 | ||||
|     protected resizeListener?: CoreEventObserver; | ||||
|     protected isDestroyed = false; | ||||
| @ -79,54 +82,41 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | ||||
| 
 | ||||
|     protected firstSelectedTab?: string; // ID of the first selected tab to control history.
 | ||||
|     protected backButtonFunction: (event: BackButtonEvent) => void; | ||||
|     protected languageChangedSubscription?: Subscription; | ||||
|     // Swiper 6 documentation: https://swiper6.vercel.app/
 | ||||
|     protected isInTransition = false; // Wether Slides is in transition.
 | ||||
|     protected slidesSwiper: any; // eslint-disable-line @typescript-eslint/no-explicit-any
 | ||||
|     protected slidesSwiperLoaded = false; | ||||
|     protected subscriptions: Subscription[] = []; | ||||
| 
 | ||||
|     tabAction: CoreTabsRoleTab<T>; | ||||
| 
 | ||||
|     constructor( | ||||
|         protected element: ElementRef, | ||||
|     ) { | ||||
|     constructor() { | ||||
|         this.backButtonFunction = this.backButtonClicked.bind(this); | ||||
| 
 | ||||
|         this.tabAction = new CoreTabsRoleTab(this); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Component being initialized. | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     ngOnInit(): void { | ||||
|     async ngOnInit(): Promise<void> { | ||||
|         this.direction = Platform.isRTL ? 'rtl' : 'ltr'; | ||||
| 
 | ||||
|         // Change the side when the language changes.
 | ||||
|         this.languageChangedSubscription = Translate.onLangChange.subscribe(() => { | ||||
|         this.subscriptions.push(Translate.onLangChange.subscribe(() => { | ||||
|             setTimeout(() => { | ||||
|                 this.direction = Platform.isRTL ? 'rtl' : 'ltr'; | ||||
|             }); | ||||
|         }); | ||||
|         })); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * View has been initialized. | ||||
|      * @inheritdoc | ||||
|      */ | ||||
|     async ngAfterViewInit(): Promise<void> { | ||||
|     ngAfterViewInit(): void { | ||||
|         if (this.isDestroyed) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.afterViewInitTriggered = true; | ||||
| 
 | ||||
|         if (!this.initialized && this.hideUntil) { | ||||
|             // Tabs should be shown, initialize them.
 | ||||
|             await this.initializeTabs(); | ||||
|         } | ||||
| 
 | ||||
|         this.resizeListener = CoreDom.onWindowResize(() => { | ||||
|             this.windowResized(); | ||||
|         }); | ||||
|         this.init(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -134,14 +124,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | ||||
|      */ | ||||
|     // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | ||||
|     ngOnChanges(changes: Record<string, SimpleChange>): void { | ||||
|         // Wait for ngAfterViewInit so it works in the case that each tab has its own component.
 | ||||
|         if (!this.initialized && this.hideUntil && this.afterViewInitTriggered) { | ||||
|             // Tabs should be shown, initialize them.
 | ||||
|             // Use a setTimeout so child components update their inputs before initializing the tabs.
 | ||||
|             setTimeout(() => { | ||||
|                 this.initializeTabs(); | ||||
|             }); | ||||
|         } | ||||
|         this.init(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -206,6 +189,16 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.numTabsShown = this.tabs.reduce((prev: number, current) => current.enabled ? prev + 1 : prev, 0); | ||||
| 
 | ||||
|         if (this.numTabsShown <= 1) { | ||||
|             this.hideTabs = true; | ||||
| 
 | ||||
|             // Only one, nothing to do here.
 | ||||
|             return; | ||||
|         } | ||||
|         this.hideTabs = false; | ||||
| 
 | ||||
|         await this.calculateMaxSlides(); | ||||
| 
 | ||||
|         await this.updateSlides(); | ||||
| @ -233,28 +226,81 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Initialize the tabs, determining the first tab to be shown. | ||||
|      * Init the component. | ||||
|      */ | ||||
|     protected async initializeTabs(): Promise<void> { | ||||
|         // Initialize slider.
 | ||||
|         this.slidesSwiper = await this.slides?.getSwiper(); | ||||
|         this.slidesSwiper.once('progress', () => { | ||||
|             this.slidesSwiperLoaded = true; | ||||
|             this.calculateSlides(); | ||||
|         }); | ||||
| 
 | ||||
|         const selectedTab = this.calculateInitialTab(); | ||||
|         if (!selectedTab) { | ||||
|     protected async init(): Promise<void> { | ||||
|         if (!this.hideUntil) { | ||||
|             // Hidden, do nothing.
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.firstSelectedTab = selectedTab.id!; | ||||
|         this.selectTab(this.firstSelectedTab); | ||||
|         try { | ||||
|             await this.initializeSlider(); | ||||
|             await this.initializeTabs(); | ||||
|         } catch { | ||||
|             // Something went wrong, ignore.
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Initialize the slider elements. | ||||
|      */ | ||||
|     protected async initializeSlider(): Promise<void> { | ||||
|         if (this.initialized) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (this.slidesElement) { | ||||
|             // Already initializated, await for ready.
 | ||||
|             await this.slidesElement.componentOnReady(); | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (!this.slides) { | ||||
|             await CoreUtils.nextTick(); | ||||
|         } | ||||
|         const slidesSwiper = await this.slides?.getSwiper(); | ||||
|         if (!slidesSwiper || !this.slides) { | ||||
|             throw new CoreError('Swiper not found, will try on next change.'); | ||||
|         } | ||||
| 
 | ||||
|         this.slidesElement = <HTMLIonSlidesElement>slidesSwiper.el; | ||||
|         await this.slidesElement.componentOnReady(); | ||||
| 
 | ||||
|         this.initialized = true; | ||||
| 
 | ||||
|         // Subscribe to changes.
 | ||||
|         this.subscriptions.push(this.slides.ionSlideDidChange.subscribe(() => { | ||||
|             this.slideChanged(); | ||||
|         })); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Initialize the tabs, determining the first tab to be shown. | ||||
|      */ | ||||
|     protected async initializeTabs(): Promise<void> { | ||||
|         if (!this.initialized || !this.slidesElement) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const selectedTab = this.calculateInitialTab(); | ||||
|         if (!selectedTab) { | ||||
|             // No enabled tabs, return.
 | ||||
|             throw new CoreError('No enabled tabs.'); | ||||
|         } | ||||
| 
 | ||||
|         this.firstSelectedTab = selectedTab.id; | ||||
|         if (this.firstSelectedTab !== undefined) { | ||||
|             this.selectTab(this.firstSelectedTab); | ||||
|         } | ||||
| 
 | ||||
|         // Check which arrows should be shown.
 | ||||
|         this.calculateSlides(); | ||||
| 
 | ||||
|         this.resizeListener = CoreDom.onWindowResize(() => { | ||||
|             this.calculateSlides(); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -277,7 +323,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | ||||
|      * Method executed when the slides are changed. | ||||
|      */ | ||||
|     async slideChanged(): Promise<void> { | ||||
|         if (!this.slidesSwiperLoaded) { | ||||
|         if (!this.slidesElement) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
| @ -302,17 +348,15 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | ||||
|      * Updates the number of slides to show. | ||||
|      */ | ||||
|     protected async updateSlides(): Promise<void> { | ||||
|         this.numTabsShown = this.tabs.reduce((prev: number, current) => current.enabled ? prev + 1 : prev, 0); | ||||
|         if (!this.slides) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.slidesOpts = { ...this.slidesOpts, slidesPerView: Math.min(this.maxSlides, this.numTabsShown) }; | ||||
| 
 | ||||
|         this.slideChanged(); | ||||
|         await this.slideChanged(); | ||||
| 
 | ||||
|         // @todo: This call to update() can trigger JS errors in the console if tabs are re-loaded and there's only 1 tab.
 | ||||
|         // For some reason, swiper.slides is undefined inside the Slides class, and the swiper is marked as destroyed.
 | ||||
|         // Changing *ngIf="hideUntil" to [hidden] doesn't solve the issue, and it causes another error to be raised.
 | ||||
|         // This can be tested in lesson as a student, play a lesson and go back to the entry page.
 | ||||
|         await this.slides!.update(); | ||||
|         await this.slides.update(); | ||||
| 
 | ||||
|         if (!this.hasSliddenToInitial && this.selectedIndex && this.selectedIndex >= this.slidesOpts.slidesPerView) { | ||||
|             this.hasSliddenToInitial = true; | ||||
| @ -320,7 +364,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | ||||
| 
 | ||||
|             setTimeout(() => { | ||||
|                 if (this.shouldSlideToInitial) { | ||||
|                     this.slides!.slideTo(this.selectedIndex, 0); | ||||
|                     this.slides?.slideTo(this.selectedIndex, 0); | ||||
|                     this.shouldSlideToInitial = false; | ||||
|                 } | ||||
|             }, 400); | ||||
| @ -339,17 +383,23 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | ||||
|      * Calculate the number of slides that can fit on the screen. | ||||
|      */ | ||||
|     protected async calculateMaxSlides(): Promise<void> { | ||||
|         if (!this.slidesSwiperLoaded) { | ||||
|         if (!this.slidesElement || !this.slides) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.maxSlides = 3; | ||||
|         let width = this.slidesSwiper.width; | ||||
|         if (!width) { | ||||
|             this.slidesSwiper.updateSize(); | ||||
|             width = this.slidesSwiper.width; | ||||
|         await CoreUtils.nextTick(); | ||||
| 
 | ||||
|         let width: number = this.slidesElement.getBoundingClientRect().width; | ||||
|         if (!width) { | ||||
|             const slidesSwiper = await this.slides.getSwiper(); | ||||
| 
 | ||||
|             await slidesSwiper.updateSize(); | ||||
|             await CoreUtils.nextTick(); | ||||
| 
 | ||||
|             width = slidesSwiper.width; | ||||
|             if (!width) { | ||||
| 
 | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
| @ -456,12 +506,12 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (this.selected) { | ||||
|         if (this.selected && this.slides) { | ||||
|             // Check if we need to slide to the tab because it's not visible.
 | ||||
|             const firstVisibleTab = await this.slides!.getActiveIndex(); | ||||
|             const firstVisibleTab = await this.slides.getActiveIndex(); | ||||
|             const lastVisibleTab = firstVisibleTab + this.slidesOpts.slidesPerView - 1; | ||||
|             if (index < firstVisibleTab || index > lastVisibleTab) { | ||||
|                 await this.slides!.slideTo(index, 0, true); | ||||
|                 await this.slides.slideTo(index, 0, true); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| @ -470,9 +520,9 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const ok = await this.loadTab(tabToSelect); | ||||
|         const suceeded = await this.loadTab(tabToSelect); | ||||
| 
 | ||||
|         if (ok !== false) { | ||||
|         if (suceeded !== false) { | ||||
|             this.tabSelected(tabToSelect, index); | ||||
|         } | ||||
|     } | ||||
| @ -503,15 +553,6 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Adapt tabs to a window resize. | ||||
|      */ | ||||
|     protected windowResized(): void { | ||||
|         setTimeout(() => { | ||||
|             this.calculateSlides(); | ||||
|         }, 200); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Component destroyed. | ||||
|      */ | ||||
| @ -519,7 +560,7 @@ export class CoreTabsBaseComponent<T extends CoreTabBase> implements OnInit, Aft | ||||
|         this.isDestroyed = true; | ||||
| 
 | ||||
|         this.resizeListener?.off(); | ||||
|         this.languageChangedSubscription?.unsubscribe(); | ||||
|         this.subscriptions.forEach((subscription) => subscription.unsubscribe()); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -541,8 +582,8 @@ class CoreTabsRoleTab<T extends CoreTabBase> extends CoreAriaRoleTab<CoreTabsBas | ||||
|      */ | ||||
|     getSelectableTabs(): CoreAriaRoleTabFindable[] { | ||||
|         return this.componentInstance.tabs.filter((tab) => tab.enabled).map((tab) => ({ | ||||
|             id: tab.id!, | ||||
|             findIndex: tab.id!, | ||||
|             id: tab.id || '', | ||||
|             findIndex: tab.id || '', | ||||
|         })); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -6,10 +6,9 @@ | ||||
|                 <ion-icon *ngIf="showPrevButton" name="fas-chevron-left" [attr.aria-label]="'core.previous' | translate"></ion-icon> | ||||
|             </ion-col> | ||||
|             <ion-col class="ion-no-padding" size="10"> | ||||
|                 <ion-slides (ionSlideDidChange)="slideChanged()" [options]="slidesOpts" [dir]="direction" role="tablist" | ||||
|                     [attr.aria-label]="description"> | ||||
|                 <ion-slides [options]="slidesOpts" [dir]="direction" role="tablist" [attr.aria-label]="description"> | ||||
|                     <ng-container *ngFor="let tab of tabs"> | ||||
|                         <ion-slide role="presentation" [id]="tab.id! + '-tab'" class="tab-slide" tabindex="-1" | ||||
|                         <ion-slide role="presentation" class="tab-slide" [id]=" tab.id! + '-tab'" tabindex="-1" | ||||
|                             [class.selected]="selected == tab.id"> | ||||
|                             <ion-tab-button (ionTabButtonClick)="selectTab(tab.id, $event)" (keydown)="tabAction.keyDown($event)" | ||||
|                                 (keyup)="tabAction.keyUp(tab.id, $event)" [tab]="tab.page" [layout]="layout" class="{{tab.class}}" | ||||
|  | ||||
| @ -70,7 +70,7 @@ export class CoreTabsOutletComponent extends CoreTabsBaseComponent<CoreTabsOutle | ||||
|     protected existsInNavigationStack = false; | ||||
| 
 | ||||
|     constructor(element: ElementRef) { | ||||
|         super(element); | ||||
|         super(); | ||||
| 
 | ||||
|         CoreComponentsRegistry.register(element.nativeElement, this); | ||||
|     } | ||||
|  | ||||
| @ -5,10 +5,9 @@ | ||||
|             <ion-icon *ngIf="showPrevButton" name="fas-chevron-left" [attr.aria-label]="'core.previous' | translate"></ion-icon> | ||||
|         </ion-col> | ||||
|         <ion-col class="ion-no-padding" size="10"> | ||||
|             <ion-slides (ionSlideDidChange)="slideChanged()" [options]="slidesOpts" [dir]="direction" role="tablist" | ||||
|                 [attr.aria-label]="description"> | ||||
|             <ion-slides [options]="slidesOpts" [dir]="direction" role="tablist" [attr.aria-label]="description"> | ||||
|                 <ng-container *ngFor="let tab of tabs"> | ||||
|                     <ion-slide *ngIf="tab.enabled" role="presentation" [hidden]="!hideUntil" class="tab-slide" [id]="tab.id! + '-tab'" | ||||
|                     <ion-slide *ngIf="tab.enabled" role="presentation" class="tab-slide" [id]="tab.id! + '-tab'" | ||||
|                         [class.selected]="selected == tab.id"> | ||||
|                         <ion-tab-button (click)="selectTab(tab.id, $event)" (keydown)="tabAction.keyDown($event)" | ||||
|                             (keyup)="tabAction.keyUp(tab.id, $event)" class="{{tab.class}}" [layout]="layout" role="tab" | ||||
|  | ||||
| @ -65,7 +65,7 @@ export class CoreTabComponent implements OnInit, OnDestroy, CoreTabBase { | ||||
|         return this.isEnabled; | ||||
|     } | ||||
| 
 | ||||
|     @Input() id?: string; // An ID to identify the tab.
 | ||||
|     @Input() id = ''; // An ID to identify the tab.
 | ||||
|     @Output() ionSelect: EventEmitter<CoreTabComponent> = new EventEmitter<CoreTabComponent>(); | ||||
| 
 | ||||
|     @ContentChild(TemplateRef) template?: TemplateRef<unknown>; // Template defined by the content.
 | ||||
| @ -82,7 +82,7 @@ export class CoreTabComponent implements OnInit, OnDestroy, CoreTabBase { | ||||
|         element: ElementRef, | ||||
|     ) { | ||||
|         this.element = element.nativeElement; | ||||
| 
 | ||||
|         this.id = this.id || 'core-tab-' + CoreUtils.getUniqueId('CoreTabComponent'); | ||||
|         this.element.setAttribute('role', 'tabpanel'); | ||||
|         this.element.setAttribute('tabindex', '0'); | ||||
|         this.element.setAttribute('aria-hidden', 'true'); | ||||
| @ -92,7 +92,6 @@ export class CoreTabComponent implements OnInit, OnDestroy, CoreTabBase { | ||||
|      * Component being initialized. | ||||
|      */ | ||||
|     ngOnInit(): void { | ||||
|         this.id = this.id || 'core-tab-' + CoreUtils.getUniqueId('CoreTabComponent'); | ||||
|         this.element.setAttribute('aria-labelledby', this.id + '-tab'); | ||||
|         this.element.setAttribute('id', this.id); | ||||
| 
 | ||||
|  | ||||
| @ -39,7 +39,7 @@ | ||||
|             ion-tab-button { | ||||
|                 max-width: 100%; | ||||
|                 ion-label { | ||||
|                     font-size: 16px; | ||||
|                     font-size: 14px; | ||||
|                     font-weight: 400; | ||||
|                     text-overflow: ellipsis; | ||||
|                     white-space: nowrap; | ||||
| @ -109,8 +109,3 @@ | ||||
|         position: relative; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| :host-context(.ios) { | ||||
|     --height: 53px; | ||||
| } | ||||
|  | ||||
| @ -51,12 +51,6 @@ export class CoreTabsComponent extends CoreTabsBaseComponent<CoreTabComponent> i | ||||
| 
 | ||||
|     protected originalTabsContainer?: HTMLElement; // The container of the original tabs. It will include each tab's content.
 | ||||
| 
 | ||||
|     constructor( | ||||
|         element: ElementRef, | ||||
|     ) { | ||||
|         super(element); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * View has been initialized. | ||||
|      */ | ||||
| @ -84,7 +78,7 @@ export class CoreTabsComponent extends CoreTabsBaseComponent<CoreTabComponent> i | ||||
|      */ | ||||
|     addTab(tab: CoreTabComponent): void { | ||||
|         // Check if tab is already in the list.
 | ||||
|         if (this.getTabIndex(tab.id!) == -1) { | ||||
|         if (this.getTabIndex(tab.id) === -1) { | ||||
|             this.tabs.push(tab); | ||||
|             this.sortTabs(); | ||||
| 
 | ||||
| @ -100,7 +94,7 @@ export class CoreTabsComponent extends CoreTabsBaseComponent<CoreTabComponent> i | ||||
|      * @param tab The tab to remove. | ||||
|      */ | ||||
|     removeTab(tab: CoreTabComponent): void { | ||||
|         const index = this.getTabIndex(tab.id!); | ||||
|         const index = this.getTabIndex(tab.id); | ||||
|         this.tabs.splice(index, 1); | ||||
| 
 | ||||
|         this.calculateSlides(); | ||||
|  | ||||
| @ -131,6 +131,7 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy { | ||||
|         } catch (error) { | ||||
|             CoreDomUtils.showErrorModal(error); | ||||
|             CoreNavigator.back(); | ||||
|             this.loaded = true; | ||||
| 
 | ||||
|             return; | ||||
|         } | ||||
| @ -224,9 +225,9 @@ export class CoreCourseIndexPage implements OnInit, OnDestroy { | ||||
|         // Select the tab if needed.
 | ||||
|         this.firstTabName = undefined; | ||||
|         if (tabToLoad) { | ||||
|             setTimeout(() => { | ||||
|                 this.tabsComponent?.selectByIndex(tabToLoad!); | ||||
|             }); | ||||
|             await CoreUtils.nextTick(); | ||||
| 
 | ||||
|             this.tabsComponent?.selectByIndex(tabToLoad); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user