mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-16 01:52:19 +08:00
fix(angular): ionTabsWillChange is fired before tab activation (#27991)
Issue number: Resolves #27212 --------- <!-- Please do not submit updates to dependencies unless it fixes an issue. --> <!-- Please try to limit your pull request to one type (bugfix, feature, etc). Submit multiple pull requests if needed. --> ## What is the current behavior? <!-- Please describe the current behavior that you are modifying. --> `ionTabsWillChange` emits _after_ the tab view is activated in the stack. ## What is the new behavior? <!-- Please describe the behavior or changes that are being added by this PR. --> - `ionTabsWillChange` emits _before_ the tab view is activated in the stack. ## Does this introduce a breaking change? - [ ] Yes - [x] No <!-- If this introduces a breaking change, please describe the impact and migration path for existing applications below. --> ## Other information <!-- Any other information that is important to this PR such as screenshots of how the component looks before and after the change. --> Dev-build: `7.2.4-dev.11692040948.1fd0ecd2`
This commit is contained in:
@ -30,7 +30,7 @@ import { Config } from '../../providers/config';
|
|||||||
import { NavController } from '../../providers/nav-controller';
|
import { NavController } from '../../providers/nav-controller';
|
||||||
|
|
||||||
import { StackController } from './stack-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
|
// TODO(FW-2827): types
|
||||||
|
|
||||||
@ -66,7 +66,11 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
|||||||
*/
|
*/
|
||||||
@Input() name = PRIMARY_OUTLET;
|
@Input() name = PRIMARY_OUTLET;
|
||||||
|
|
||||||
@Output() stackEvents = new EventEmitter<any>();
|
/** @internal */
|
||||||
|
@Output() stackWillChange = new EventEmitter<StackWillChangeEvent>();
|
||||||
|
/** @internal */
|
||||||
|
@Output() stackDidChange = new EventEmitter<StackDidChangeEvent>();
|
||||||
|
|
||||||
// eslint-disable-next-line @angular-eslint/no-output-rename
|
// eslint-disable-next-line @angular-eslint/no-output-rename
|
||||||
@Output('activate') activateEvents = new EventEmitter<any>();
|
@Output('activate') activateEvents = new EventEmitter<any>();
|
||||||
// eslint-disable-next-line @angular-eslint/no-output-rename
|
// eslint-disable-next-line @angular-eslint/no-output-rename
|
||||||
@ -304,9 +308,16 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
|
|||||||
*/
|
*/
|
||||||
this.navCtrl.setTopOutlet(this);
|
this.navCtrl.setTopOutlet(this);
|
||||||
|
|
||||||
|
const leavingView = this.stackCtrl.getActiveView();
|
||||||
|
|
||||||
|
this.stackWillChange.emit({
|
||||||
|
enteringView,
|
||||||
|
tabSwitch: isTabSwitch(enteringView, leavingView),
|
||||||
|
});
|
||||||
|
|
||||||
this.stackCtrl.setActive(enteringView).then((data) => {
|
this.stackCtrl.setActive(enteringView).then((data) => {
|
||||||
this.activateEvents.emit(cmpRef.instance);
|
this.activateEvents.emit(cmpRef.instance);
|
||||||
this.stackEvents.emit(data);
|
this.stackDidChange.emit(data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,14 +16,19 @@ import { NavController } from '../../providers/nav-controller';
|
|||||||
import { IonTabBar } from '../proxies';
|
import { IonTabBar } from '../proxies';
|
||||||
|
|
||||||
import { IonRouterOutlet } from './ion-router-outlet';
|
import { IonRouterOutlet } from './ion-router-outlet';
|
||||||
import { StackEvent } from './stack-utils';
|
import { StackDidChangeEvent, StackWillChangeEvent } from './stack-utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ion-tabs',
|
selector: 'ion-tabs',
|
||||||
template: `
|
template: `
|
||||||
<ng-content select="[slot=top]"></ng-content>
|
<ng-content select="[slot=top]"></ng-content>
|
||||||
<div class="tabs-inner" #tabsInner>
|
<div class="tabs-inner" #tabsInner>
|
||||||
<ion-router-outlet #outlet tabs="true" (stackEvents)="onPageSelected($event)"></ion-router-outlet>
|
<ion-router-outlet
|
||||||
|
#outlet
|
||||||
|
tabs="true"
|
||||||
|
(stackWillChange)="onStackWillChange($event)"
|
||||||
|
(stackDidChange)="onStackDidChange($event)"
|
||||||
|
></ion-router-outlet>
|
||||||
</div>
|
</div>
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
`,
|
`,
|
||||||
@ -62,7 +67,13 @@ export class IonTabs implements AfterContentInit, AfterContentChecked {
|
|||||||
@ContentChild(IonTabBar, { static: false }) tabBar: IonTabBar | undefined;
|
@ContentChild(IonTabBar, { static: false }) tabBar: IonTabBar | undefined;
|
||||||
@ContentChildren(IonTabBar) tabBars: QueryList<IonTabBar>;
|
@ContentChildren(IonTabBar) tabBars: QueryList<IonTabBar>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted before the tab view is changed.
|
||||||
|
*/
|
||||||
@Output() ionTabsWillChange = new EventEmitter<{ tab: string }>();
|
@Output() ionTabsWillChange = new EventEmitter<{ tab: string }>();
|
||||||
|
/**
|
||||||
|
* Emitted after the tab view is changed.
|
||||||
|
*/
|
||||||
@Output() ionTabsDidChange = new EventEmitter<{ tab: string }>();
|
@Output() ionTabsDidChange = new EventEmitter<{ tab: string }>();
|
||||||
|
|
||||||
private tabBarSlot = 'bottom';
|
private tabBarSlot = 'bottom';
|
||||||
@ -80,10 +91,19 @@ export class IonTabs implements AfterContentInit, AfterContentChecked {
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
onPageSelected(detail: StackEvent): void {
|
onStackWillChange({ enteringView, tabSwitch }: StackWillChangeEvent): void {
|
||||||
const stackId = detail.enteringView.stackId;
|
const stackId = enteringView.stackId;
|
||||||
if (detail.tabSwitch && stackId !== undefined) {
|
if (tabSwitch && stackId !== undefined) {
|
||||||
this.ionTabsWillChange.emit({ tab: stackId });
|
this.ionTabsWillChange.emit({ tab: stackId });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
onStackDidChange({ enteringView, tabSwitch }: StackDidChangeEvent): void {
|
||||||
|
const stackId = enteringView.stackId;
|
||||||
|
if (tabSwitch && stackId !== undefined) {
|
||||||
if (this.tabBar) {
|
if (this.tabBar) {
|
||||||
this.tabBar.selectedTab = stackId;
|
this.tabBar.selectedTab = stackId;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import { NavController } from '../../providers/nav-controller';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
RouteView,
|
RouteView,
|
||||||
StackEvent,
|
StackDidChangeEvent,
|
||||||
computeStackId,
|
computeStackId,
|
||||||
destroyView,
|
destroyView,
|
||||||
getUrl,
|
getUrl,
|
||||||
@ -61,7 +61,7 @@ export class StackController {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
setActive(enteringView: RouteView): Promise<StackEvent> {
|
setActive(enteringView: RouteView): Promise<StackDidChangeEvent> {
|
||||||
const consumeResult = this.navCtrl.consumeTransition();
|
const consumeResult = this.navCtrl.consumeTransition();
|
||||||
let { direction, animation, animationBuilder } = consumeResult;
|
let { direction, animation, animationBuilder } = consumeResult;
|
||||||
const leavingView = this.activeView;
|
const leavingView = this.activeView;
|
||||||
@ -224,6 +224,13 @@ export class StackController {
|
|||||||
return this.activeView ? this.activeView.stackId : undefined;
|
return this.activeView ? this.activeView.stackId : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
getActiveView(): RouteView | undefined {
|
||||||
|
return this.activeView;
|
||||||
|
}
|
||||||
|
|
||||||
hasRunningTask(): boolean {
|
hasRunningTask(): boolean {
|
||||||
return this.runningTask !== undefined;
|
return this.runningTask !== undefined;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
enteringView: RouteView;
|
||||||
direction: RouterDirection;
|
direction: RouterDirection;
|
||||||
animation: NavDirection | undefined;
|
animation: NavDirection | undefined;
|
||||||
|
/**
|
||||||
|
* `true` if the event is trigged as a result of a switch
|
||||||
|
* between tab navigation stacks.
|
||||||
|
*/
|
||||||
tabSwitch: boolean;
|
tabSwitch: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user