mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-17 02:31:34 +08:00
fix(router-outlet): change detection fires properly (#18896)
* fix(router-outlet): never detach() the entering view fixes #18894 * add tests * ci * update package-lock * circle sync runtime
This commit is contained in:
@ -173,6 +173,9 @@ jobs:
|
||||
- run:
|
||||
command: npm install
|
||||
working_directory: /tmp/workspace/angular/test/test-app
|
||||
- run:
|
||||
command: npm run sync
|
||||
working_directory: /tmp/workspace/angular/test/test-app
|
||||
- run:
|
||||
command: npm test
|
||||
working_directory: /tmp/workspace/angular/test/test-app
|
||||
|
@ -44,7 +44,11 @@ export class StackController {
|
||||
|
||||
getExistingView(activatedRoute: ActivatedRoute): RouteView | undefined {
|
||||
const activatedUrlKey = getUrl(this.router, activatedRoute);
|
||||
return this.views.find(vw => vw.url === activatedUrlKey);
|
||||
const view = this.views.find(vw => vw.url === activatedUrlKey);
|
||||
if (view) {
|
||||
view.ref.changeDetectorRef.reattach();
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
setActive(enteringView: RouteView): Promise<StackEvent> {
|
||||
@ -55,6 +59,7 @@ export class StackController {
|
||||
direction = 'back';
|
||||
animation = undefined;
|
||||
}
|
||||
|
||||
const viewsSnapshot = this.views.slice();
|
||||
|
||||
let currentNavigation;
|
||||
@ -208,14 +213,19 @@ export class StackController {
|
||||
this.skipTransition = false;
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
if (enteringView) {
|
||||
enteringView.ref.changeDetectorRef.reattach();
|
||||
if (leavingView === enteringView) {
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
// disconnect leaving page from change detection to
|
||||
// reduce jank during the page transition
|
||||
if (leavingView) {
|
||||
leavingView.ref.changeDetectorRef.detach();
|
||||
}
|
||||
// In case the enteringView is the same as the leavingPage we need to reattach()
|
||||
if (enteringView) {
|
||||
enteringView.ref.changeDetectorRef.reattach();
|
||||
}
|
||||
const enteringEl = enteringView ? enteringView.element : undefined;
|
||||
const leavingEl = leavingView ? leavingView.element : undefined;
|
||||
const containerEl = this.containerEl;
|
||||
|
@ -25,9 +25,6 @@ export class IonicRouteStrategy implements RouteReuseStrategy {
|
||||
if (future.routeConfig !== curr.routeConfig) {
|
||||
return false;
|
||||
}
|
||||
if (future.component !== curr.component) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// checking router params
|
||||
const futureParams = future.params;
|
||||
|
@ -20,7 +20,7 @@ describe('tabs', () => {
|
||||
it('should simulate stack + double tab click', async () => {
|
||||
let tab = await getSelectedTab() as ElementFinder;
|
||||
await tab.$('#goto-tab1-page2').click();
|
||||
await testTabTitle('Tab 1 - Page 2');
|
||||
await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested']);
|
||||
await testState(1, 'account');
|
||||
expect(await tab.$('ion-back-button').isDisplayed()).toBe(true);
|
||||
@ -31,7 +31,7 @@ describe('tabs', () => {
|
||||
await testState(2, 'contact');
|
||||
|
||||
await element(by.css('#tab-button-account')).click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2');
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1', 'app-tabs-tab1-nested', 'app-tabs-tab2']);
|
||||
await testState(3, 'account');
|
||||
expect(await tab.$('ion-back-button').isDisplayed()).toBe(true);
|
||||
@ -45,7 +45,7 @@ describe('tabs', () => {
|
||||
it('should simulate stack + back button click', async () => {
|
||||
const tab = await getSelectedTab();
|
||||
await tab.$('#goto-tab1-page2').click();
|
||||
await testTabTitle('Tab 1 - Page 2');
|
||||
await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
await testState(1, 'account');
|
||||
|
||||
await element(by.css('#tab-button-contact')).click();
|
||||
@ -53,7 +53,7 @@ describe('tabs', () => {
|
||||
await testState(2, 'contact');
|
||||
|
||||
await element(by.css('#tab-button-account')).click();
|
||||
await testTabTitle('Tab 1 - Page 2');
|
||||
await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
await testState(3, 'account');
|
||||
|
||||
await element(by.css('ion-back-button')).click();
|
||||
@ -62,6 +62,33 @@ describe('tabs', () => {
|
||||
await testState(3, 'account');
|
||||
});
|
||||
|
||||
it('should navigate deep then go home', async () => {
|
||||
let tab = await getSelectedTab();
|
||||
await tab.$('#goto-tab1-page2').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
|
||||
await tab.$('#goto-next').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (2)');
|
||||
|
||||
await element(by.css('#tab-button-contact')).click();
|
||||
tab = await testTabTitle('Tab 2 - Page 1');
|
||||
|
||||
await element(by.css('#tab-button-account')).click();
|
||||
await testTabTitle('Tab 1 - Page 2 (2)');
|
||||
await testStack('ion-tabs ion-router-outlet', [
|
||||
'app-tabs-tab1',
|
||||
'app-tabs-tab1-nested',
|
||||
'app-tabs-tab1-nested',
|
||||
'app-tabs-tab2'
|
||||
]);
|
||||
await element(by.css('#tab-button-account')).click();
|
||||
await testTabTitle('Tab 1 - Page 1');
|
||||
await testStack('ion-tabs ion-router-outlet', [
|
||||
'app-tabs-tab1',
|
||||
'app-tabs-tab2'
|
||||
]);
|
||||
});
|
||||
|
||||
it('should switch tabs and go back', async () => {
|
||||
await element(by.css('#tab-button-contact')).click();
|
||||
const tab = await testTabTitle('Tab 2 - Page 1');
|
||||
@ -76,7 +103,7 @@ describe('tabs', () => {
|
||||
const tab = await testTabTitle('Tab 2 - Page 1');
|
||||
|
||||
await tab.$('#goto-tab1-page2').click();
|
||||
await testTabTitle('Tab 1 - Page 2');
|
||||
await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab2', 'app-tabs-tab1-nested']);
|
||||
});
|
||||
|
||||
@ -97,14 +124,14 @@ describe('tabs', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('entry url - /tabs/account/nested/12', () => {
|
||||
describe('entry url - /tabs/account/nested/1', () => {
|
||||
beforeEach(async () => {
|
||||
await browser.get('/tabs/account/nested/12');
|
||||
await browser.get('/tabs/account/nested/1');
|
||||
await waitTime(30);
|
||||
});
|
||||
|
||||
it('should only display the back-button when there is a page in the stack', async () => {
|
||||
let tab = await testTabTitle('Tab 1 - Page 2') as ElementFinder;
|
||||
let tab = await testTabTitle('Tab 1 - Page 2 (1)') as ElementFinder;
|
||||
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1-nested']);
|
||||
expect(await tab.$('ion-back-button').isDisplayed()).toBe(false);
|
||||
|
||||
@ -112,9 +139,32 @@ describe('tabs', () => {
|
||||
tab = await testTabTitle('Tab 1 - Page 1');
|
||||
|
||||
await tab.$('#goto-tab1-page2').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2');
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
expect(await tab.$('ion-back-button').isDisplayed()).toBe(true);
|
||||
});
|
||||
|
||||
it('should not reuse the same page', async () => {
|
||||
let tab = await testTabTitle('Tab 1 - Page 2 (1)') as ElementFinder;
|
||||
await tab.$('#goto-next').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (2)');
|
||||
await tab.$('#goto-next').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (3)');
|
||||
|
||||
await testStack('ion-tabs ion-router-outlet',[
|
||||
'app-tabs-tab1-nested',
|
||||
'app-tabs-tab1-nested',
|
||||
'app-tabs-tab1-nested'
|
||||
]);
|
||||
|
||||
await tab.$('ion-back-button').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (2)');
|
||||
await tab.$('ion-back-button').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
|
||||
expect(await tab.$('ion-back-button').isDisplayed()).toBe(false);
|
||||
|
||||
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab1-nested']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('entry url - /tabs/lazy', () => {
|
||||
@ -128,7 +178,7 @@ describe('tabs', () => {
|
||||
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab3']);
|
||||
|
||||
await tab.$('#goto-tab1-page2').click();
|
||||
tab = await testTabTitle('Tab 1 - Page 2');
|
||||
tab = await testTabTitle('Tab 1 - Page 2 (1)');
|
||||
await testStack('ion-tabs ion-router-outlet', ['app-tabs-tab3', 'app-tabs-tab1-nested']);
|
||||
expect(await tab.$('ion-back-button').isDisplayed()).toBe(false);
|
||||
});
|
||||
|
5943
angular/test/test-app/package-lock.json
generated
5943
angular/test/test-app/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -13,29 +13,28 @@
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~7.2.1",
|
||||
"@angular/common": "~7.2.1",
|
||||
"@angular/compiler": "~7.2.1",
|
||||
"@angular/core": "~7.2.1",
|
||||
"@angular/forms": "~7.2.1",
|
||||
"@angular/platform-browser": "~7.2.1",
|
||||
"@angular/platform-browser-dynamic": "~7.2.1",
|
||||
"@angular/router": "~7.2.1",
|
||||
"@ionic/angular": "^4.5.0",
|
||||
"@angular/animations": "~8.1.2",
|
||||
"@angular/common": "~8.1.2",
|
||||
"@angular/compiler": "~8.1.2",
|
||||
"@angular/core": "~8.1.2",
|
||||
"@angular/forms": "~8.1.2",
|
||||
"@angular/platform-browser": "~8.1.2",
|
||||
"@angular/platform-browser-dynamic": "~8.1.2",
|
||||
"@angular/router": "~8.1.2",
|
||||
"@ionic/angular": "^4.7.0",
|
||||
"core-js": "^2.6.2",
|
||||
"rxjs": "~6.3.3",
|
||||
"rxjs": "^6.4.0",
|
||||
"tslib": "^1.9.0",
|
||||
"zone.js": "~0.8.26"
|
||||
"zone.js": "~0.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.12.2",
|
||||
"@angular/cli": "~7.2.1",
|
||||
"@angular/compiler-cli": "~7.2.1",
|
||||
"@angular/language-service": "~7.2.1",
|
||||
"@angular-devkit/build-angular": "^0.801.2",
|
||||
"@angular/cli": "~8.1.2",
|
||||
"@angular/compiler-cli": "~8.1.2",
|
||||
"@angular/language-service": "~8.1.2",
|
||||
"@types/jasmine": "~2.8.8",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/node": "~8.9.4",
|
||||
"codelyzer": "~4.5.0",
|
||||
"jasmine-core": "~2.99.1",
|
||||
"jasmine-spec-reporter": "~4.2.1",
|
||||
"karma": "~3.1.4",
|
||||
@ -46,6 +45,6 @@
|
||||
"protractor": "~5.4.2",
|
||||
"ts-node": "~7.0.0",
|
||||
"tslint": "~5.12.1",
|
||||
"typescript": "~3.2.4"
|
||||
"typescript": "~3.4.0"
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ export class AlertComponent {
|
||||
role: 'cancel',
|
||||
text: 'Cancel',
|
||||
handler: () => {
|
||||
console.log(NgZone.isInAngularZone());
|
||||
NgZone.assertInAngularZone();
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,6 @@ import { RouterLinkPageComponent } from './router-link-page/router-link-page.com
|
||||
import { RouterLinkPage2Component } from './router-link-page2/router-link-page2.component';
|
||||
import { RouterLinkPage3Component } from './router-link-page3/router-link-page3.component';
|
||||
import { HomePageComponent } from './home-page/home-page.component';
|
||||
import { TabsComponent } from './tabs/tabs.component';
|
||||
import { TabsTab1Component } from './tabs-tab1/tabs-tab1.component';
|
||||
import { TabsTab1NestedComponent } from './tabs-tab1-nested/tabs-tab1-nested.component';
|
||||
import { TabsTab2Component } from './tabs-tab2/tabs-tab2.component';
|
||||
import { VirtualScrollComponent } from './virtual-scroll/virtual-scroll.component';
|
||||
import { VirtualScrollDetailComponent } from './virtual-scroll-detail/virtual-scroll-detail.component';
|
||||
import { NestedOutletComponent } from './nested-outlet/nested-outlet.component';
|
||||
@ -51,40 +47,7 @@ const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: 'tabs',
|
||||
component: TabsComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'account',
|
||||
children: [
|
||||
{
|
||||
path: 'nested/:id',
|
||||
component: TabsTab1NestedComponent
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: TabsTab1Component
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'contact',
|
||||
children: [
|
||||
{
|
||||
path: 'one',
|
||||
component: TabsTab2Component
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'one',
|
||||
pathMatch: 'full'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'lazy',
|
||||
loadChildren: './tabs-lazy/tabs-lazy.module#TabsLazyModule'
|
||||
}
|
||||
]
|
||||
loadChildren: './tabs/tabs.module#TabsPageModule'
|
||||
},
|
||||
{
|
||||
path: 'nested-outlet',
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { RouteReuseStrategy } from '@angular/router';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { InputsComponent } from './inputs/inputs.component';
|
||||
import { ModalComponent } from './modal/modal.component';
|
||||
@ -14,10 +15,6 @@ import { RouterLinkPageComponent } from './router-link-page/router-link-page.com
|
||||
import { RouterLinkPage2Component } from './router-link-page2/router-link-page2.component';
|
||||
import { RouterLinkPage3Component } from './router-link-page3/router-link-page3.component';
|
||||
import { HomePageComponent } from './home-page/home-page.component';
|
||||
import { TabsComponent } from './tabs/tabs.component';
|
||||
import { TabsTab1Component } from './tabs-tab1/tabs-tab1.component';
|
||||
import { TabsTab2Component } from './tabs-tab2/tabs-tab2.component';
|
||||
import { TabsTab1NestedComponent } from './tabs-tab1-nested/tabs-tab1-nested.component';
|
||||
import { VirtualScrollComponent } from './virtual-scroll/virtual-scroll.component';
|
||||
import { VirtualScrollDetailComponent } from './virtual-scroll-detail/virtual-scroll-detail.component';
|
||||
import { VirtualScrollInnerComponent } from './virtual-scroll-inner/virtual-scroll-inner.component';
|
||||
@ -45,10 +42,6 @@ import { AlertComponent } from './alert/alert.component';
|
||||
RouterLinkPage2Component,
|
||||
RouterLinkPage3Component,
|
||||
HomePageComponent,
|
||||
TabsComponent,
|
||||
TabsTab1Component,
|
||||
TabsTab2Component,
|
||||
TabsTab1NestedComponent,
|
||||
VirtualScrollComponent,
|
||||
VirtualScrollDetailComponent,
|
||||
VirtualScrollInnerComponent,
|
||||
@ -76,7 +69,9 @@ import { AlertComponent } from './alert/alert.component';
|
||||
ModalExampleComponent,
|
||||
NavComponent
|
||||
],
|
||||
providers: [],
|
||||
providers: [
|
||||
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
@ -6,7 +6,7 @@ import { IonSlides } from '@ionic/angular';
|
||||
templateUrl: './slides.component.html',
|
||||
})
|
||||
export class SlidesComponent implements AfterViewInit {
|
||||
@ViewChild(IonSlides) slides: IonSlides;
|
||||
@ViewChild(IonSlides, {static: true}) slides: IonSlides;
|
||||
|
||||
slideIndex = 0;
|
||||
slideIndex2 = 0;
|
||||
|
@ -10,6 +10,6 @@
|
||||
<ion-content padding>
|
||||
<p>
|
||||
<ion-button routerLink="/tabs/account" id="goto-tab1-page1">Go to Tab 1 - Page 1</ion-button>
|
||||
<ion-button routerLink="/tabs/account/nested/12" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
|
||||
<ion-button routerLink="/tabs/account/nested/1" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
|
||||
</p>
|
||||
</ion-content>
|
||||
|
@ -8,7 +8,7 @@
|
||||
<h1>LAZY LOADED TAB</h1>
|
||||
<p>
|
||||
<ion-button routerLink="/tabs/account" id="goto-tab1-page1">Go to Tab 1 - Page 1</ion-button>
|
||||
<ion-button routerLink="/tabs/account/nested/12" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
|
||||
<ion-button routerLink="/tabs/account/nested/1" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
|
||||
<ion-button routerLink="/tabs/lazy/nested" id="goto-tab3-page2">Go to Tab 3 - Page 2</ion-button>
|
||||
|
||||
</p>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Tab 1 - Page 2</ion-title>
|
||||
<ion-title>Tab 1 - Page 2 ({{id}})</ion-title>
|
||||
<ion-buttons slot="start">
|
||||
<ion-back-button></ion-back-button>
|
||||
</ion-buttons>
|
||||
@ -8,9 +8,10 @@
|
||||
</ion-header>
|
||||
|
||||
<ion-content padding>
|
||||
<h1>Welcome to NESTED PAGE</h1>
|
||||
<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/account/nested/{{next()}}" id="goto-next">Go to Next</ion-button>
|
||||
</p>
|
||||
</ion-content>
|
||||
|
@ -1,7 +1,21 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Component, Input } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tabs-tab1-nested',
|
||||
templateUrl: './tabs-tab1-nested.component.html',
|
||||
})
|
||||
export class TabsTab1NestedComponent { }
|
||||
export class TabsTab1NestedComponent {
|
||||
id = '';
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.id = this.route.snapshot.paramMap.get('id');
|
||||
}
|
||||
|
||||
next() {
|
||||
return parseInt(this.id, 10) + 1;
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Tab 1 - Page 1</ion-title>
|
||||
<ion-title>{{title}}</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content padding>
|
||||
<h1>Welcome to Tab1</h1>
|
||||
<p>
|
||||
<ion-button routerLink="/tabs/account/nested/12" id="goto-tab1-page2">Go to Page 2</ion-button>
|
||||
<ion-button routerLink="/tabs/account/nested/1" id="goto-tab1-page2">Go to Page 2</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>
|
||||
</p>
|
||||
|
@ -1,7 +1,17 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, NgZone } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tabs-tab1',
|
||||
templateUrl: './tabs-tab1.component.html',
|
||||
})
|
||||
export class TabsTab1Component { }
|
||||
export class TabsTab1Component {
|
||||
title = 'ERROR';
|
||||
|
||||
ionViewWillEnter() {
|
||||
NgZone.assertInAngularZone();
|
||||
setTimeout(() => {
|
||||
NgZone.assertInAngularZone();
|
||||
this.title = 'Tab 1 - Page 1';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Tab 2 - Page 1</ion-title>
|
||||
<ion-title>{{title}}</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
<h1>Welcome to Tab 2</h1>
|
||||
<p>
|
||||
<ion-button routerLink="/tabs/account" id="goto-tab1-page1">Go to Tab 1 - Page 1</ion-button>
|
||||
<ion-button routerLink="/tabs/account/nested/12" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
|
||||
<ion-button routerLink="/tabs/account/nested/1" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
|
||||
<ion-button routerLink="/nested-outlet/page" id="goto-nested-page1">Go to nested</ion-button>
|
||||
</p>
|
||||
</ion-content>
|
||||
|
@ -1,7 +1,17 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, NgZone } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-tabs-tab2',
|
||||
templateUrl: './tabs-tab2.component.html',
|
||||
})
|
||||
export class TabsTab2Component { }
|
||||
export class TabsTab2Component {
|
||||
title = 'ERROR';
|
||||
|
||||
ngOnInit() {
|
||||
NgZone.assertInAngularZone();
|
||||
setTimeout(() => {
|
||||
NgZone.assertInAngularZone();
|
||||
this.title = 'Tab 2 - Page 1';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
27
angular/test/test-app/src/app/tabs/tabs.module.ts
Executable file
27
angular/test/test-app/src/app/tabs/tabs.module.ts
Executable file
@ -0,0 +1,27 @@
|
||||
import { IonicModule } from '@ionic/angular';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { TabsPageRoutingModule } from './tabs.router.module';
|
||||
import { TabsComponent } from './tabs.component';
|
||||
import { TabsTab1Component } from '../tabs-tab1/tabs-tab1.component';
|
||||
import { TabsTab2Component } from '../tabs-tab2/tabs-tab2.component';
|
||||
import { TabsTab1NestedComponent } from '../tabs-tab1-nested/tabs-tab1-nested.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
IonicModule,
|
||||
CommonModule,
|
||||
FormsModule,
|
||||
TabsPageRoutingModule
|
||||
],
|
||||
declarations: [
|
||||
TabsComponent,
|
||||
TabsTab1Component,
|
||||
TabsTab2Component,
|
||||
TabsTab1NestedComponent
|
||||
]
|
||||
})
|
||||
export class TabsPageModule {}
|
52
angular/test/test-app/src/app/tabs/tabs.router.module.ts
Executable file
52
angular/test/test-app/src/app/tabs/tabs.router.module.ts
Executable file
@ -0,0 +1,52 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { TabsComponent } from './tabs.component';
|
||||
import { TabsTab1NestedComponent } from '../tabs-tab1-nested/tabs-tab1-nested.component';
|
||||
import { TabsTab1Component } from '../tabs-tab1/tabs-tab1.component';
|
||||
import { TabsTab2Component } from '../tabs-tab2/tabs-tab2.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: TabsComponent,
|
||||
children: [
|
||||
{
|
||||
path: 'account',
|
||||
children: [
|
||||
{
|
||||
path: 'nested/:id',
|
||||
component: TabsTab1NestedComponent
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
component: TabsTab1Component
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'contact',
|
||||
children: [
|
||||
{
|
||||
path: 'one',
|
||||
component: TabsTab2Component
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'one',
|
||||
pathMatch: 'full'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'lazy',
|
||||
loadChildren: '../tabs-lazy/tabs-lazy.module#TabsLazyModule'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class TabsPageRoutingModule {}
|
@ -7,11 +7,11 @@ import { IonTabs, IonButton, IonSlides, IonSlide } from '@ionic/angular';
|
||||
})
|
||||
export class ViewChildComponent implements AfterViewInit {
|
||||
|
||||
@ViewChild(IonSlides) slides: IonSlides;
|
||||
@ViewChild(IonButton) button: IonButton;
|
||||
@ViewChild(IonTabs) tabs: IonTabs;
|
||||
@ViewChild('div') div: ElementRef;
|
||||
@ViewChild('slide') slide: IonSlide;
|
||||
@ViewChild(IonSlides, {static: true}) slides: IonSlides;
|
||||
@ViewChild(IonButton, {static: true}) button: IonButton;
|
||||
@ViewChild(IonTabs, {static: true}) tabs: IonTabs;
|
||||
@ViewChild('div', {static: true}) div: ElementRef;
|
||||
@ViewChild('slide', {static: true}) slide: IonSlide;
|
||||
|
||||
ngAfterViewInit() {
|
||||
const loaded = !!(this.slides && this.button && this.tabs && this.div && this.slide);
|
||||
|
@ -8,7 +8,7 @@ import { IonVirtualScroll } from '@ionic/angular';
|
||||
})
|
||||
export class VirtualScrollComponent {
|
||||
|
||||
@ViewChild(IonVirtualScroll) virtualScroll: IonVirtualScroll;
|
||||
@ViewChild(IonVirtualScroll, {static: true}) virtualScroll: IonVirtualScroll;
|
||||
|
||||
items = Array.from({length: 100}, (_, i) => ({ name: `${i}`, checked: true}));
|
||||
|
||||
|
Reference in New Issue
Block a user