Skip to content

Commit

Permalink
fix(angular): nav controller can pop views after leaving tabs outlet (#…
Browse files Browse the repository at this point in the history
…25690)

Resolves #18593
  • Loading branch information
sean-perkins committed Sep 8, 2022
1 parent 2969169 commit 725b13f
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 3 deletions.
13 changes: 12 additions & 1 deletion angular/src/directives/navigation/ion-router-outlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,19 @@ export class IonRouterOutlet implements OnDestroy, OnInit {
}

this.activatedView = enteringView;

/**
* The top outlet is set prior to the entering view's transition completing,
* so that when we have nested outlets (e.g. ion-tabs inside an ion-router-outlet),
* the tabs outlet will be assigned as the top outlet when a view inside tabs is
* activated.
*
* In this scenario, activeWith is called for both the tabs and the root router outlet.
* To avoid a race condition, we assign the top outlet synchronously.
*/
this.navCtrl.setTopOutlet(this);

this.stackCtrl.setActive(enteringView).then((data) => {
this.navCtrl.setTopOutlet(this);
this.activateEvents.emit(cmpRef.instance);
this.stackEvents.emit(data);
});
Expand Down
68 changes: 68 additions & 0 deletions angular/test/base/e2e/src/tabs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,74 @@ describe('Tabs', () => {
});
})

describe('entry url - /tabs/account', () => {
beforeEach(() => {
cy.visit('/tabs/account');
});
it('should pop to previous view when leaving tabs outlet', () => {

cy.get('ion-title').should('contain.text', 'Tab 1 - Page 1');

cy.get('#goto-tab1-page2').click();

cy.get('ion-title').should('contain.text', 'Tab 1 - Page 2 (1)');

cy.get('#goto-global').click();

cy.get('ion-title').should('contain.text', 'Global Page');

cy.get('#goto-prev-pop').click();

cy.get('ion-title').should('contain.text', 'Tab 1 - Page 2 (1)');

cy.get('#goto-prev').click();

cy.get('ion-title').should('contain.text', 'Tab 1 - Page 1');

/**
* Verifies that when entering the tabs outlet directly,
* the navController.pop() method does not pop the previous view,
* when you are at the root of the tabs outlet.
*/
cy.get('#goto-previous-page').click();
cy.get('ion-title').should('contain.text', 'Tab 1 - Page 1');
});
});

describe('entry url - /', () => {
it('should pop to the root outlet from the tabs outlet', () => {
cy.visit('/');

cy.get('ion-title').should('contain.text', 'Test App');

cy.get('ion-item').contains('Tabs test').click();

cy.get('ion-title').should('contain.text', 'Tab 1 - Page 1');

cy.get('#goto-tab1-page2').click();

cy.get('ion-title').should('contain.text', 'Tab 1 - Page 2 (1)');

cy.get('#goto-global').click();

cy.get('ion-title').should('contain.text', 'Global Page');

cy.get('#goto-prev-pop').click();

cy.get('ion-title').should('contain.text', 'Tab 1 - Page 2 (1)');

cy.get('#goto-prev').click();

cy.get('ion-title').should('contain.text', 'Tab 1 - Page 1');

cy.get('#goto-previous-page').click();

cy.get('ion-title').should('contain.text', 'Test App');

});
});


describe('entry url - /tabs/account/nested/1', () => {
beforeEach(() => {
cy.visit('/tabs/account/nested/1');
Expand Down
6 changes: 5 additions & 1 deletion angular/test/base/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ const routes: Routes = [
path: 'tabs',
loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule)
},
{
path: 'tabs-global',
loadChildren: () => import('./tabs-global/tabs-global.module').then(m => m.TabsGlobalModule)
},
{
path: 'nested-outlet',
component: NestedOutletComponent,
Expand All @@ -68,7 +72,7 @@ const routes: Routes = [
component: NestedOutletPage2Component
}
]
}
},
];

@NgModule({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { NgModule } from "@angular/core";
import { RouterModule } from "@angular/router";
import { TabsGlobalComponent } from "./tabs-global.component";

@NgModule({
imports: [
RouterModule.forChild([
{
path: '',
component: TabsGlobalComponent
}
])
],
exports: [RouterModule]
})
export class TabsGlobalRoutingModule { }
17 changes: 17 additions & 0 deletions angular/test/base/src/app/tabs-global/tabs-global.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>

<ion-title>
Global Page
</ion-title>
</ion-toolbar>
</ion-header>

<ion-content>
<ion-content>
<ion-button id="goto-prev-pop" (click)="navCtrl.pop()">Go To Previous</ion-button>
</ion-content>
</ion-content>
17 changes: 17 additions & 0 deletions angular/test/base/src/app/tabs-global/tabs-global.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Component } from "@angular/core";
import { NavController } from "@ionic/angular";

/**
* This component is used in conjunction with a tabs router-outlet,
* to validate the behavior of different routing APIs (e.g. NavController)
* when leaving and re-entering a router-outlet.
*/
@Component({
selector: 'app-tabs-global',
templateUrl: 'tabs-global.component.html'
})
export class TabsGlobalComponent {

constructor(public navCtrl: NavController) { }

}
13 changes: 13 additions & 0 deletions angular/test/base/src/app/tabs-global/tabs-global.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { NgModule } from "@angular/core";
import { IonicModule } from "@ionic/angular";
import { TabsGlobalRoutingModule } from "./tabs-global-routing.module";
import { TabsGlobalComponent } from "./tabs-global.component";

@NgModule({
imports: [
IonicModule,
TabsGlobalRoutingModule
],
declarations: [TabsGlobalComponent]
})
export class TabsGlobalModule { }
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ <h1>Welcome to NESTED PAGE {{id}}</h1>
<p>
<ion-button routerLink="/tabs/account" id="goto-tab1-page1">Go to Tab 1 - Page 1</ion-button>
<ion-button routerLink="/tabs/contact" id="goto-tab2-page1">Go to Tab 2 - Page 1</ion-button>
<ion-button routerLink="/tabs-global" id="goto-global">Go to Global Page</ion-button>
<ion-button routerLink="/tabs-global" id="goto-prev" (click)="navCtrl.pop()">Go to Previous Page (NavController).
</ion-button>
<ion-button routerLink="/tabs/account/nested/{{next()}}" id="goto-next">Go to Next</ion-button>
</p>
</ion-content>
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ActivatedRoute } from '@angular/router';
import { Component, OnInit } from '@angular/core';
import { NavController } from '@ionic/angular';

@Component({
selector: 'app-tabs-tab1-nested',
Expand All @@ -9,7 +10,8 @@ export class TabsTab1NestedComponent implements OnInit {
id = '';
constructor(
private route: ActivatedRoute,
) {}
public navCtrl: NavController
) { }

ngOnInit() {
this.id = this.route.snapshot.paramMap.get('id');
Expand All @@ -18,4 +20,5 @@ export class TabsTab1NestedComponent implements OnInit {
next() {
return parseInt(this.id, 10) + 1;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ <h1>Welcome to Tab1</h1>
id="goto-nested-page1-with-query-params">Go to Page 2 with Query Params</ion-button>
<ion-button routerLink="/tabs/lazy/nested" id="goto-tab3-page2">Go to Tab 3 - Page 2</ion-button>
<ion-button routerLink="/nested-outlet/page" id="goto-nested-page1">Go to nested</ion-button>
<ion-button (click)="navCtrl.pop()" id="goto-previous-page">Go to Previous Page</ion-button>
</p>
</ion-content>
3 changes: 3 additions & 0 deletions angular/test/base/src/app/tabs-tab1/tabs-tab1.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Component, NgZone } from '@angular/core';
import { NavController } from '@ionic/angular';

@Component({
selector: 'app-tabs-tab1',
Expand All @@ -9,6 +10,8 @@ export class TabsTab1Component {
segment = 'one';
changed = 'false';

constructor(public navCtrl: NavController) {}

ionViewWillEnter() {
NgZone.assertInAngularZone();
setTimeout(() => {
Expand Down

0 comments on commit 725b13f

Please sign in to comment.