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