From bbfb8f81a61475d7e73b63743db5d6a0cd979d21 Mon Sep 17 00:00:00 2001 From: Sean Perkins Date: Fri, 18 Aug 2023 11:07:09 -0400 Subject: [PATCH] fix(angular): ionTabsWillChange is fired before tab activation (#27991) Issue number: Resolves #27212 --------- ## What is the current behavior? `ionTabsWillChange` emits _after_ the tab view is activated in the stack. ## What is the new behavior? - `ionTabsWillChange` emits _before_ the tab view is activated in the stack. ## Does this introduce a breaking change? - [ ] Yes - [x] No ## Other information Dev-build: `7.2.4-dev.11692040948.1fd0ecd2` --- .../navigation/ion-router-outlet.ts | 17 +++++++++-- .../src/directives/navigation/ion-tabs.ts | 30 +++++++++++++++---- .../directives/navigation/stack-controller.ts | 11 +++++-- .../src/directives/navigation/stack-utils.ts | 15 +++++++++- 4 files changed, 62 insertions(+), 11 deletions(-) diff --git a/packages/angular/src/directives/navigation/ion-router-outlet.ts b/packages/angular/src/directives/navigation/ion-router-outlet.ts index c54eaa17f3..118c2fd7b6 100644 --- a/packages/angular/src/directives/navigation/ion-router-outlet.ts +++ b/packages/angular/src/directives/navigation/ion-router-outlet.ts @@ -30,7 +30,7 @@ import { Config } from '../../providers/config'; import { NavController } from '../../providers/nav-controller'; import { StackController } from './stack-controller'; -import { RouteView, getUrl } from './stack-utils'; +import { RouteView, StackDidChangeEvent, StackWillChangeEvent, getUrl, isTabSwitch } from './stack-utils'; // TODO(FW-2827): types @@ -66,7 +66,11 @@ export class IonRouterOutlet implements OnDestroy, OnInit { */ @Input() name = PRIMARY_OUTLET; - @Output() stackEvents = new EventEmitter(); + /** @internal */ + @Output() stackWillChange = new EventEmitter(); + /** @internal */ + @Output() stackDidChange = new EventEmitter(); + // eslint-disable-next-line @angular-eslint/no-output-rename @Output('activate') activateEvents = new EventEmitter(); // eslint-disable-next-line @angular-eslint/no-output-rename @@ -304,9 +308,16 @@ export class IonRouterOutlet implements OnDestroy, OnInit { */ this.navCtrl.setTopOutlet(this); + const leavingView = this.stackCtrl.getActiveView(); + + this.stackWillChange.emit({ + enteringView, + tabSwitch: isTabSwitch(enteringView, leavingView), + }); + this.stackCtrl.setActive(enteringView).then((data) => { this.activateEvents.emit(cmpRef.instance); - this.stackEvents.emit(data); + this.stackDidChange.emit(data); }); } diff --git a/packages/angular/src/directives/navigation/ion-tabs.ts b/packages/angular/src/directives/navigation/ion-tabs.ts index 1fa8965218..08ce66d36f 100644 --- a/packages/angular/src/directives/navigation/ion-tabs.ts +++ b/packages/angular/src/directives/navigation/ion-tabs.ts @@ -16,14 +16,19 @@ import { NavController } from '../../providers/nav-controller'; import { IonTabBar } from '../proxies'; import { IonRouterOutlet } from './ion-router-outlet'; -import { StackEvent } from './stack-utils'; +import { StackDidChangeEvent, StackWillChangeEvent } from './stack-utils'; @Component({ selector: 'ion-tabs', template: `
- +
`, @@ -62,7 +67,13 @@ export class IonTabs implements AfterContentInit, AfterContentChecked { @ContentChild(IonTabBar, { static: false }) tabBar: IonTabBar | undefined; @ContentChildren(IonTabBar) tabBars: QueryList; + /** + * Emitted before the tab view is changed. + */ @Output() ionTabsWillChange = new EventEmitter<{ tab: string }>(); + /** + * Emitted after the tab view is changed. + */ @Output() ionTabsDidChange = new EventEmitter<{ tab: string }>(); private tabBarSlot = 'bottom'; @@ -80,10 +91,19 @@ export class IonTabs implements AfterContentInit, AfterContentChecked { /** * @internal */ - onPageSelected(detail: StackEvent): void { - const stackId = detail.enteringView.stackId; - if (detail.tabSwitch && stackId !== undefined) { + onStackWillChange({ enteringView, tabSwitch }: StackWillChangeEvent): void { + const stackId = enteringView.stackId; + if (tabSwitch && stackId !== undefined) { this.ionTabsWillChange.emit({ tab: stackId }); + } + } + + /** + * @internal + */ + onStackDidChange({ enteringView, tabSwitch }: StackDidChangeEvent): void { + const stackId = enteringView.stackId; + if (tabSwitch && stackId !== undefined) { if (this.tabBar) { this.tabBar.selectedTab = stackId; } diff --git a/packages/angular/src/directives/navigation/stack-controller.ts b/packages/angular/src/directives/navigation/stack-controller.ts index 93520c0a66..673ff34d02 100644 --- a/packages/angular/src/directives/navigation/stack-controller.ts +++ b/packages/angular/src/directives/navigation/stack-controller.ts @@ -8,7 +8,7 @@ import { NavController } from '../../providers/nav-controller'; import { RouteView, - StackEvent, + StackDidChangeEvent, computeStackId, destroyView, getUrl, @@ -61,7 +61,7 @@ export class StackController { return view; } - setActive(enteringView: RouteView): Promise { + setActive(enteringView: RouteView): Promise { const consumeResult = this.navCtrl.consumeTransition(); let { direction, animation, animationBuilder } = consumeResult; const leavingView = this.activeView; @@ -224,6 +224,13 @@ export class StackController { return this.activeView ? this.activeView.stackId : undefined; } + /** + * @internal + */ + getActiveView(): RouteView | undefined { + return this.activeView; + } + hasRunningTask(): boolean { return this.runningTask !== undefined; } diff --git a/packages/angular/src/directives/navigation/stack-utils.ts b/packages/angular/src/directives/navigation/stack-utils.ts index ae33e03ce7..dda4ecac7b 100644 --- a/packages/angular/src/directives/navigation/stack-utils.ts +++ b/packages/angular/src/directives/navigation/stack-utils.ts @@ -79,10 +79,23 @@ export const destroyView = (view: RouteView | undefined): void => { } }; -export interface StackEvent { +export interface StackWillChangeEvent { + enteringView: RouteView; + /** + * `true` if the event is trigged as a result of a switch + * between tab navigation stacks. + */ + tabSwitch: boolean; +} + +export interface StackDidChangeEvent { enteringView: RouteView; direction: RouterDirection; animation: NavDirection | undefined; + /** + * `true` if the event is trigged as a result of a switch + * between tab navigation stacks. + */ tabSwitch: boolean; }