test(angular): add support for multi-version testing (#25665)

This commit is contained in:
Liam DeBeasi
2022-08-18 15:46:15 -05:00
committed by GitHub
parent 436a8ce508
commit 08dd3e277b
155 changed files with 63791 additions and 58 deletions

View File

@ -0,0 +1,17 @@
<ion-content>
<ion-button id="dismiss" (click)="modal.dismiss()">Dismiss Modal</ion-button>
<ion-accordion-group [value]="'a'">
<ion-accordion value="a">
<ion-item slot="header">
<ion-label>A</ion-label>
</ion-item>
<div slot="content">A content</div>
</ion-accordion>
<ion-accordion value="b">
<ion-item slot="header">
<ion-label>B</ion-label>
</ion-item>
<div slot="content">B content</div>
</ion-accordion>
</ion-accordion-group>
</ion-content>

View File

@ -0,0 +1,11 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-accordion-modal',
templateUrl: './accordion-modal.component.html',
})
export class AccordionModalComponent {
modal: HTMLIonModalElement;
constructor() {}
}

View File

@ -0,0 +1,13 @@
<ion-header>
<ion-toolbar>
<ion-buttons>
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>
Accordion test
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-button id="open-modal" (click)="open()">Open Modal</ion-button>
</ion-content>

View File

@ -0,0 +1,22 @@
import { Component } from '@angular/core';
import { ModalController } from '@ionic/angular';
import { AccordionModalComponent } from './accordion-modal/accordion-modal.component';
@Component({
selector: 'app-accordion',
templateUrl: './accordion.component.html',
})
export class AccordionComponent {
constructor(
private modalCtrl: ModalController
) { }
async open() {
const modal = await this.modalCtrl.create({
component: AccordionModalComponent,
animated: false,
});
await modal.present();
}
}

View File

@ -0,0 +1,13 @@
<ion-header>
<ion-toolbar>
<ion-buttons>
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>
Alert test
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<p>Change Detections: <span id="counter">{{counter()}}</span></p>
</ion-content>

View File

@ -0,0 +1,39 @@
import { Component, NgZone } from '@angular/core';
import { AlertController } from '@ionic/angular';
import { NavComponent } from '../nav/nav.component';
@Component({
selector: 'app-alert',
templateUrl: './alert.component.html',
})
export class AlertComponent {
changes = 0;
constructor(
private alertCtrl: AlertController
) { }
counter() {
this.changes++;
return Math.floor(this.changes / 2);
}
async openAlert() {
const alert = await this.alertCtrl.create({
header: 'Hello',
message: 'Some text',
buttons: [
{
role: 'cancel',
text: 'Cancel',
handler: () => {
console.log(NgZone.isInAngularZone());
NgZone.assertInAngularZone();
}
}
]
});
await alert.present();
}
}

View File

@ -0,0 +1,78 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { InputsComponent } from './inputs/inputs.component';
import { ModalComponent } from './modal/modal.component';
import { RouterLinkComponent } from './router-link/router-link.component';
import { RouterLinkPageComponent } from './router-link-page/router-link-page.component';
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 { 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';
import { NestedOutletPageComponent } from './nested-outlet-page/nested-outlet-page.component';
import { NestedOutletPage2Component } from './nested-outlet-page2/nested-outlet-page2.component';
import { ViewChildComponent } from './view-child/view-child.component';
import { ProvidersComponent } from './providers/providers.component';
import { SlidesComponent } from './slides/slides.component';
import { FormComponent } from './form/form.component';
import { NavigationPage1Component } from './navigation-page1/navigation-page1.component';
import { NavigationPage2Component } from './navigation-page2/navigation-page2.component';
import { NavigationPage3Component } from './navigation-page3/navigation-page3.component';
import { AlertComponent } from './alert/alert.component';
import { AccordionComponent } from './accordion/accordion.component';
const routes: Routes = [
{ path: '', component: HomePageComponent },
{ path: 'version-test', loadChildren: () => import('./version-test').then(m => m.VersionTestModule) },
{ path: 'accordions', component: AccordionComponent },
{ path: 'alerts', component: AlertComponent },
{ path: 'inputs', component: InputsComponent },
{ path: 'form', component: FormComponent },
{ path: 'modals', component: ModalComponent },
{ path: 'modal-inline', loadChildren: () => import('./modal-inline').then(m => m.ModalInlineModule) },
{ path: 'view-child', component: ViewChildComponent },
{ path: 'keep-contents-mounted', loadChildren: () => import('./keep-contents-mounted').then(m => m.OverlayAutoMountModule) },
{ path: 'popover-inline', loadChildren: () => import('./popover-inline').then(m => m.PopoverInlineModule) },
{ path: 'providers', component: ProvidersComponent },
{ path: 'router-link', component: RouterLinkComponent },
{ path: 'router-link-page', component: RouterLinkPageComponent },
{ path: 'router-link-page2/:id', component: RouterLinkPage2Component },
{ path: 'router-link-page3', component: RouterLinkPage3Component },
{ path: 'slides', component: SlidesComponent },
{ path: 'virtual-scroll', component: VirtualScrollComponent },
{ path: 'virtual-scroll-detail/:itemId', component: VirtualScrollDetailComponent },
{ path: 'tabs', redirectTo: '/tabs/account', pathMatch: 'full' },
{
path: 'navigation',
children: [
{ path: 'page1', component: NavigationPage1Component },
{ path: 'page2', component: NavigationPage2Component },
{ path: 'page3', component: NavigationPage3Component }
]
},
{
path: 'tabs',
loadChildren: () => import('./tabs/tabs.module').then(m => m.TabsPageModule)
},
{
path: 'nested-outlet',
component: NestedOutletComponent,
children: [
{
path: 'page',
component: NestedOutletPageComponent
},
{
path: 'page2',
component: NestedOutletPage2Component
}
]
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }

View File

@ -0,0 +1,3 @@
<ion-app>
<ion-router-outlet></ion-router-outlet>
</ion-app>

View File

@ -0,0 +1,9 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
}

View File

@ -0,0 +1,77 @@
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, IonicRouteStrategy } from '@ionic/angular';
import { FormsModule } from '@angular/forms';
import { InputsComponent } from './inputs/inputs.component';
import { ModalComponent } from './modal/modal.component';
import { ModalExampleComponent } from './modal-example/modal-example.component';
import { RouterLinkComponent } from './router-link/router-link.component';
import { RouterLinkPageComponent } from './router-link-page/router-link-page.component';
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 { 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';
import { NestedOutletComponent } from './nested-outlet/nested-outlet.component';
import { NestedOutletPageComponent } from './nested-outlet-page/nested-outlet-page.component';
import { NestedOutletPage2Component } from './nested-outlet-page2/nested-outlet-page2.component';
import { NavComponent } from './nav/nav.component';
import { ViewChildComponent } from './view-child/view-child.component';
import { ProvidersComponent } from './providers/providers.component';
import { SlidesComponent } from './slides/slides.component';
import { FormComponent } from './form/form.component';
import { NavigationPage1Component } from './navigation-page1/navigation-page1.component';
import { NavigationPage2Component } from './navigation-page2/navigation-page2.component';
import { NavigationPage3Component } from './navigation-page3/navigation-page3.component';
import { AlertComponent } from './alert/alert.component';
import { AccordionComponent } from './accordion/accordion.component';
import { AccordionModalComponent } from './accordion/accordion-modal/accordion-modal.component';
@NgModule({
declarations: [
AppComponent,
InputsComponent,
ModalComponent,
ModalExampleComponent,
RouterLinkComponent,
RouterLinkPageComponent,
RouterLinkPage2Component,
RouterLinkPage3Component,
HomePageComponent,
VirtualScrollComponent,
VirtualScrollDetailComponent,
VirtualScrollInnerComponent,
NestedOutletComponent,
NestedOutletPageComponent,
NestedOutletPage2Component,
NavComponent,
ViewChildComponent,
ProvidersComponent,
SlidesComponent,
FormComponent,
NavigationPage1Component,
NavigationPage2Component,
NavigationPage3Component,
AlertComponent,
AccordionComponent,
AccordionModalComponent
],
imports: [
BrowserModule.withServerTransition({ appId: 'serverApp' }),
AppRoutingModule,
FormsModule,
ReactiveFormsModule,
IonicModule.forRoot({ keyboardHeight: 12345 }),
],
providers: [
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
],
bootstrap: [AppComponent]
})
export class AppModule { }

View File

@ -0,0 +1,15 @@
import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { IonicServerModule } from '@ionic/angular-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
@NgModule({
imports: [
AppModule,
ServerModule,
IonicServerModule
],
bootstrap: [AppComponent],
})
export class AppServerModule {}

View File

@ -0,0 +1,83 @@
<ion-header>
<ion-toolbar>
<ion-title>
Forms test
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<form [formGroup]="profileForm" (ngSubmit)="onSubmit($event)">
<ion-list>
<ion-item>
<ion-label>DateTime</ion-label>
<ion-datetime formControlName="datetime" min="1994-03-14" max="2017-12-09" display-format="MM/DD/YYYY">
</ion-datetime>
</ion-item>
<ion-item>
<ion-label>Select</ion-label>
<ion-select formControlName="select">
<ion-select-option value="">No Game Console</ion-select-option>
<ion-select-option value="nes">NES</ion-select-option>
<ion-select-option value="n64" selected>Nintendo64</ion-select-option>
<ion-select-option value="ps">PlayStation</ion-select-option>
<ion-select-option value="genesis">Sega Genesis</ion-select-option>
<ion-select-option value="saturn">Sega Saturn</ion-select-option>
<ion-select-option value="snes">SNES</ion-select-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Toggle</ion-label>
<ion-toggle formControlName="toggle" slot="end"></ion-toggle>
</ion-item>
<ion-item>
<ion-label>Input (required)</ion-label>
<ion-input formControlName="input" class="required" id="touched-input-test"></ion-input>
</ion-item>
<ion-button id="input-touched" (click)="setTouched()">Set Input Touched</ion-button>
<ion-item>
<ion-label>Input</ion-label>
<ion-input formControlName="input2"></ion-input>
</ion-item>
<ion-item>
<ion-label>Checkbox</ion-label>
<ion-checkbox formControlName="checkbox" slot="start"></ion-checkbox>
</ion-item>
<ion-item>
<ion-label>Range</ion-label>
<ion-range formControlName="range"></ion-range>
</ion-item>
</ion-list>
<p>
Form Status: <span id="status">{{ profileForm.status }}</span>
</p>
<p>
Form Status: <span id="data">{{ profileForm.value | json }}</span>
</p>
<p>
Form Submit: <span id="submit">{{submitted}}</span>
</p>
<ion-button id="mark-all-touched-button" (click)="markAllAsTouched()">Mark all as touched</ion-button>
<ion-button id="submit-button" type="submit" [disabled]="!profileForm.valid">Submit</ion-button>
</form>
<ion-list>
<ion-item>
<ion-label>Outside form</ion-label>
<ion-toggle [formControl]="outsideToggle"></ion-toggle>
<ion-note slot="end">{{outsideToggle.value}}</ion-note>
</ion-item>
</ion-list>
<p>
<ion-button (click)="setValues()" id="set-values">Set values</ion-button>
</p>
</ion-content>

View File

@ -0,0 +1,53 @@
import { Component } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, Validators, UntypedFormControl } from '@angular/forms';
@Component({
selector: 'app-form',
templateUrl: './form.component.html',
})
export class FormComponent {
submitted = 'false';
profileForm: UntypedFormGroup;
outsideToggle = new UntypedFormControl(true);
constructor(fb: UntypedFormBuilder) {
this.profileForm = fb.group({
datetime: ['2010-08-20', Validators.required],
select: [undefined, Validators.required],
toggle: [false],
input: ['', Validators.required],
input2: ['Default Value'],
checkbox: [false],
range: [5, Validators.min(10)],
}, {
updateOn: typeof (window as any) !== 'undefined' && window.location.hash === '#blur' ? 'blur' : 'change'
});
}
setTouched() {
const formControl = this.profileForm.get('input');
formControl.markAsTouched();
}
onSubmit(_ev) {
this.submitted = 'true';
}
setValues() {
this.profileForm.patchValue({
datetime: '2010-08-20',
select: 'nes',
toggle: true,
input: 'Some value',
input2: 'Another values',
checkbox: true,
range: 50
});
}
markAllAsTouched() {
this.profileForm.markAllAsTouched();
}
}

View File

@ -0,0 +1,71 @@
<ion-header>
<ion-toolbar>
<ion-title>
Test App
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item routerLink="/alerts" [routerAnimation]="routerAnimation">
<ion-label>
Alerts test
</ion-label>
</ion-item>
<ion-item routerLink="/inputs">
<ion-label>
Inputs test
</ion-label>
</ion-item>
<ion-item routerLink="/form">
<ion-label>
Form test
</ion-label>
</ion-item>
<ion-item routerLink="/modals">
<ion-label>
Modals test
</ion-label>
</ion-item>
<ion-item routerLink="/router-link">
<ion-label>
Router link test
</ion-label>
</ion-item>
<ion-item routerLink="/tabs">
<ion-label>
Tabs test
</ion-label>
</ion-item>
<ion-item routerLink="/slides">
<ion-label>
Slides test
</ion-label>
</ion-item>
<ion-item routerLink="/virtual-scroll">
<ion-label>
Virtual Scroll
</ion-label>
</ion-item>
<ion-item routerLink="/nested-outlet/page">
<ion-label>
Nested ion-router-outlet
</ion-label>
</ion-item>
<ion-item routerLink="/view-child">
<ion-label>
ViewChild()
</ion-label>
</ion-item>
<ion-item routerLink="/providers">
<ion-label>
Providers
</ion-label>
</ion-item>
<ion-item routerLink="/accordions">
<ion-label>
Accordions Test
</ion-label>
</ion-item>
</ion-list>
</ion-content>

View File

@ -0,0 +1,25 @@
import { Component } from '@angular/core';
import { AnimationBuilder, AnimationController } from '@ionic/angular';
@Component({
selector: 'app-home-page',
templateUrl: './home-page.component.html',
})
export class HomePageComponent {
routerAnimation: AnimationBuilder = (_, opts) => {
const { direction, enteringEl, leavingEl } = opts;
const animation = this.animationCtrl.create().duration(500).easing('ease-out');
const enteringAnimation = this.animationCtrl.create().addElement(enteringEl).beforeRemoveClass(['ion-page-invisible']);
const leavingAnimation = this.animationCtrl.create().addElement(leavingEl).beforeRemoveClass(['ion-page-invisible']);
if (direction === 'back') {
enteringAnimation.fromTo('transform', 'translateX(-100%)', 'translateX(0%)');
leavingAnimation.fromTo('transform', 'translateX(0%)', 'translateX(100%)');
} else {
enteringAnimation.fromTo('transform', 'translateX(100%)', 'translateX(0%)');
leavingAnimation.fromTo('transform', 'translateX(0%)', 'translateX(-100%)');
}
return animation.addAnimation([enteringAnimation, leavingAnimation]);
};
constructor(private animationCtrl: AnimationController) {}
}

View File

@ -0,0 +1,107 @@
<ion-header>
<ion-toolbar>
<ion-title>
Inputs test
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<p>Change Detections: <span id="counter">{{counter()}}</span></p>
<ion-list>
<ion-item>
<ion-label>DateTime</ion-label>
<ion-datetime [(ngModel)]="datetime" min="1994-03-14" max="2017-12-09" display-format="MM/DD/YYYY"></ion-datetime>
<ion-note slot="end" id="datetime-note">{{datetime}}</ion-note>
</ion-item>
<ion-item color="dark">
<ion-label>DateTime Mirror</ion-label>
<ion-datetime [(ngModel)]="datetime" min="1994-03-14" max="2017-12-09" display-format="MM/DD/YYYY"></ion-datetime>
<ion-note slot="end">{{datetime}}</ion-note>
</ion-item>
<ion-item>
<ion-label>Select</ion-label>
<ion-select [(ngModel)]="select">
<ion-select-option value="">No Game Console</ion-select-option>
<ion-select-option value="nes">NES</ion-select-option>
<ion-select-option value="n64" selected>Nintendo64</ion-select-option>
<ion-select-option value="ps">PlayStation</ion-select-option>
<ion-select-option value="genesis">Sega Genesis</ion-select-option>
<ion-select-option value="saturn">Sega Saturn</ion-select-option>
<ion-select-option value="snes">SNES</ion-select-option>
</ion-select>
<ion-note slot="end" id="select-note">{{select}}</ion-note>
</ion-item>
<ion-item color="dark">
<ion-label>Select Mirror</ion-label>
<ion-select [(ngModel)]="select">
<ion-select-option value="">No Game Console</ion-select-option>
<ion-select-option value="nes">NES</ion-select-option>
<ion-select-option value="n64" selected>Nintendo64</ion-select-option>
<ion-select-option value="ps">PlayStation</ion-select-option>
<ion-select-option value="genesis">Sega Genesis</ion-select-option>
<ion-select-option value="saturn">Sega Saturn</ion-select-option>
<ion-select-option value="snes">SNES</ion-select-option>
</ion-select>
<ion-note slot="end">{{select}}</ion-note>
</ion-item>
<ion-item>
<ion-label>Toggle</ion-label>
<ion-toggle [(ngModel)]="toggle" slot="end"></ion-toggle>
<ion-note slot="end" id="toggle-note">{{toggle}}</ion-note>
</ion-item>
<ion-item color="dark">
<ion-label>Toggle Mirror</ion-label>
<ion-toggle [(ngModel)]="toggle" slot="end"></ion-toggle>
<ion-note slot="end">{{toggle}}</ion-note>
</ion-item>
<ion-item>
<ion-label>Input</ion-label>
<ion-input [(ngModel)]="input"></ion-input>
<ion-note slot="end" id="input-note">{{input}}</ion-note>
</ion-item>
<ion-item color="dark">
<ion-label>Input Mirror</ion-label>
<ion-input [(ngModel)]="input"></ion-input>
<ion-note slot="end">{{input}}</ion-note>
</ion-item>
<ion-item>
<ion-label>Checkbox</ion-label>
<ion-checkbox [(ngModel)]="checkbox" slot="start"></ion-checkbox>
<ion-note slot="end" id="checkbox-note">{{checkbox}}</ion-note>
</ion-item>
<ion-item color="dark">
<ion-label>Checkbox Mirror</ion-label>
<ion-checkbox [(ngModel)]="checkbox" slot="start"></ion-checkbox>
<ion-note slot="end">{{checkbox}}</ion-note>
</ion-item>
<ion-item>
<ion-label>Range</ion-label>
<ion-range [(ngModel)]="range"></ion-range>
<ion-note slot="end" id="range-note">{{range}}</ion-note>
</ion-item>
<ion-item color="dark">
<ion-label>Range Mirror</ion-label>
<ion-range [(ngModel)]="range">
<ion-toggle slot="start" id="nested-toggle" [(ngModel)]="toggle"></ion-toggle>
</ion-range>
<ion-note slot="end">{{range}}</ion-note>
</ion-item>
</ion-list>
<p>
<ion-button (click)="setValues()" id="set-button">Set values</ion-button>
<ion-button (click)="resetValues()" id="reset-button">Reset values</ion-button>
</p>
</ion-content>

View File

@ -0,0 +1,40 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-inputs',
templateUrl: './inputs.component.html',
})
export class InputsComponent {
datetime = '1994-03-15';
input = 'some text';
checkbox = true;
toggle = true;
select = 'nes';
range = 10;
changes = 0;
setValues() {
console.log('set values');
this.datetime = '1994-03-15';
this.input = 'some text';
this.checkbox = true;
this.toggle = true;
this.select = 'nes';
this.range = 10;
}
resetValues() {
console.log('reset values');
this.datetime = undefined;
this.input = undefined;
this.checkbox = false;
this.toggle = false;
this.select = undefined;
this.range = undefined;
}
counter() {
this.changes++;
return Math.floor(this.changes / 2);
}
}

View File

@ -0,0 +1,2 @@
export * from './keep-contents-mounted.component';
export * from './keep-contents-mounted.module';

View File

@ -0,0 +1,16 @@
import { NgModule } from "@angular/core";
import { RouterModule } from "@angular/router";
import { OverlayKeepContentsMounted } from ".";
@NgModule({
imports: [
RouterModule.forChild([
{
path: '',
component: OverlayKeepContentsMounted
}
])
],
exports: [RouterModule]
})
export class OverlayKeepContentsMountedRoutingModule { }

View File

@ -0,0 +1,22 @@
<ion-content>
<ion-button id="open-modal" (click)="modal.present()">Open Modal</ion-button>
<ion-button id="open-popover" (click)="popover.present()">Open Popover</ion-button>
<ion-modal [keepContentsMounted]="true" #modal>
<ng-template>
<ion-content>
<ion-button (click)="modal.dismiss()">Dismiss</ion-button>
Modal Content
</ion-content>
</ng-template>
</ion-modal>
<ion-popover [keepContentsMounted]="true" #popover>
<ng-template>
<ion-content>
<ion-button (click)="popover.dismiss()">Dismiss</ion-button>
Popover Content
</ion-content>
</ng-template>
</ion-popover>
</ion-content>

View File

@ -0,0 +1,13 @@
import { Component } from "@angular/core";
/**
* Validates that inline modals correctly mount
* inner components when keepContentsMounted is
* enabled.
*/
@Component({
selector: 'app-keep-contents-mounted',
templateUrl: 'keep-contents-mounted.component.html'
})
export class OverlayKeepContentsMounted {
}

View File

@ -0,0 +1,12 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { IonicModule } from "@ionic/angular";
import { OverlayKeepContentsMountedRoutingModule } from "./keep-contents-mounted-routing.module";
import { OverlayKeepContentsMounted } from "./keep-contents-mounted.component";
@NgModule({
imports: [CommonModule, IonicModule, OverlayKeepContentsMountedRoutingModule],
declarations: [OverlayKeepContentsMounted],
exports: [OverlayKeepContentsMounted]
})
export class OverlayAutoMountModule { }

View File

@ -0,0 +1,35 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-button (click)="closeModal()" id="close-modal">
Close
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<h1>Value</h1>
<h2>{{value}}</h2>
<h3>{{valueFromParams}}</h3>
<p>modal is defined: <span id="modalInstance">{{ !!modal }}</span></p>
<p>ngOnInit: <span id="ngOnInit">{{onInit}}</span></p>
<p>ionViewWillEnter: <span id="ionViewWillEnter">{{willEnter}}</span></p>
<p>ionViewDidEnter: <span id="ionViewDidEnter">{{didEnter}}</span></p>
<p>ionViewWillLeave: <span id="ionViewWillLeave">{{willLeave}}</span></p>
<p>ionViewDidLeave: <span id="ionViewDidLeave">{{didLeave}}</span></p>
<p *ngIf="!!nav">
<ion-button (click)="push()" class="push-page">Push page</ion-button>
<ion-button (click)="pop()" class="pop-page">Pop page</ion-button>
</p>
<form [formGroup]="form">
<ion-item id="inputWithFloatingLabel">
<ion-label color="primary" position="floating">Floating Label</ion-label>
<ion-select multiple="false" formControlName="select">
<ion-select-option [value]="0">Option 0</ion-select-option>
<ion-select-option [value]="1">Option 1</ion-select-option>
</ion-select>
</ion-item>
</form>
</ion-content>

View File

@ -0,0 +1,70 @@
import { Component, Input, NgZone, OnInit, Optional } from '@angular/core';
import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { ModalController, NavParams, IonNav, ViewWillLeave, ViewDidEnter, ViewDidLeave } from '@ionic/angular';
@Component({
selector: 'app-modal-example',
templateUrl: './modal-example.component.html',
})
export class ModalExampleComponent implements OnInit, ViewWillLeave, ViewDidEnter, ViewWillLeave, ViewDidLeave {
@Input() value: string;
form = new UntypedFormGroup({
select: new UntypedFormControl([])
});
valueFromParams: string;
onInit = 0;
willEnter = 0;
didEnter = 0;
willLeave = 0;
didLeave = 0;
modal: HTMLElement;
constructor(
private modalCtrl: ModalController,
@Optional() public nav: IonNav,
navParams: NavParams
) {
this.valueFromParams = navParams.get('prop');
}
ngOnInit() {
NgZone.assertInAngularZone();
this.onInit++;
}
ionViewWillEnter() {
if (this.onInit !== 1) {
throw new Error('ngOnInit was not called');
}
NgZone.assertInAngularZone();
this.willEnter++;
}
ionViewDidEnter() {
NgZone.assertInAngularZone();
this.didEnter++;
}
ionViewWillLeave() {
NgZone.assertInAngularZone();
this.willLeave++;
}
ionViewDidLeave() {
NgZone.assertInAngularZone();
this.didLeave++;
}
closeModal() {
this.modalCtrl.dismiss();
}
push() {
this.nav.push(ModalExampleComponent, {
'value': 'pushed!'
});
}
pop() {
this.nav.pop();
}
}

View File

@ -0,0 +1,2 @@
export * from './modal-inline.component';
export * from './modal-inline.module';

View File

@ -0,0 +1,16 @@
import { NgModule } from "@angular/core";
import { RouterModule } from "@angular/router";
import { ModalInlineComponent } from ".";
@NgModule({
imports: [
RouterModule.forChild([
{
path: '',
component: ModalInlineComponent
}
])
],
exports: [RouterModule]
})
export class ModalInlineRoutingModule { }

View File

@ -0,0 +1,20 @@
<ion-button id="open-modal">Open Modal</ion-button>
<ul>
<li>
breakpointDidChange event count: <span id="breakpointDidChange">{{ breakpointDidChangeCounter }}</span>
</li>
</ul>
<ion-modal [animated]="false" trigger="open-modal" [breakpoints]="[0.1, 0.5, 1]" [initialBreakpoint]="0.5"
(ionBreakpointDidChange)="onBreakpointDidChange()">
<ng-template>
<ion-content>
<ion-list>
<ion-item *ngFor="let item of items">
<ion-label>{{ item }}</ion-label>
</ion-item>
</ion-list>
</ion-content>
</ng-template>
</ion-modal>

View File

@ -0,0 +1,27 @@
import { AfterViewInit, Component } from "@angular/core";
/**
* Validates that inline modals will correctly display
* dynamic contents that are updated after the modal is
* display.
*/
@Component({
selector: 'app-modal-inline',
templateUrl: 'modal-inline.component.html'
})
export class ModalInlineComponent implements AfterViewInit {
items: string[] = [];
breakpointDidChangeCounter = 0;
ngAfterViewInit(): void {
setTimeout(() => {
this.items = ['A', 'B', 'C', 'D'];
}, 1000);
}
onBreakpointDidChange() {
this.breakpointDidChangeCounter++;
}
}

View File

@ -0,0 +1,12 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { IonicModule } from "@ionic/angular";
import { ModalInlineRoutingModule } from "./modal-inline-routing.module";
import { ModalInlineComponent } from "./modal-inline.component";
@NgModule({
imports: [CommonModule, IonicModule, ModalInlineRoutingModule],
declarations: [ModalInlineComponent],
exports: [ModalInlineComponent]
})
export class ModalInlineModule { }

View File

@ -0,0 +1,17 @@
<ion-header>
<ion-toolbar>
<ion-title>
Modal test
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<ion-button (click)="openModal()" id="action-button">Open Modal</ion-button>
<ion-button (click)="openNav()" id="action-button-2">Open Nav in Modal</ion-button>
<p>
onWillDismiss: <span id="onWillDismiss">{{onWillDismiss}}</span>
</p>
<p>
onDidDismiss: <span id="onDidDismiss">{{onDidDismiss}}</span>
</p>
</ion-content>

View File

@ -0,0 +1,49 @@
import { Component, NgZone } from '@angular/core';
import { ModalController } from '@ionic/angular';
import { ModalExampleComponent } from '../modal-example/modal-example.component';
import { NavComponent } from '../nav/nav.component';
@Component({
selector: 'app-modal',
templateUrl: './modal.component.html',
})
export class ModalComponent {
onWillDismiss = false;
onDidDismiss = false;
constructor(
private modalCtrl: ModalController
) { }
async openModal() {
return this.open(ModalExampleComponent);
}
async openNav() {
return this.open(NavComponent);
}
async open(TheModalComponent: any) {
const modal = await this.modalCtrl.create({
component: TheModalComponent,
animated: false,
componentProps: {
value: '123',
prop: '321'
}
});
await modal.present();
modal.onWillDismiss().then(() => {
NgZone.assertInAngularZone();
this.onWillDismiss = true;
});
modal.onDidDismiss().then(() => {
NgZone.assertInAngularZone();
if (!this.onWillDismiss) {
throw new Error('onWillDismiss should be emitted first');
}
this.onDidDismiss = true;
});
}
}

View File

@ -0,0 +1 @@
<ion-nav [root]="rootPage" [rootParams]="rootParams"></ion-nav>

View File

@ -0,0 +1,20 @@
import { Component } from '@angular/core';
import { ModalExampleComponent } from '../modal-example/modal-example.component';
import { NavParams } from '@ionic/angular';
@Component({
selector: 'app-nav',
templateUrl: './nav.component.html',
})
export class NavComponent {
rootPage = ModalExampleComponent;
rootParams: any;
constructor(
params: NavParams
) {
this.rootParams = {
...params.data
};
}
}

View File

@ -0,0 +1,3 @@
<p>
navigation-page1 works!
</p>

View File

@ -0,0 +1,20 @@
import { Component } from '@angular/core';
import { NavController } from '@ionic/angular';
let count = 0;
@Component({
selector: 'app-navigation-page1',
templateUrl: './navigation-page1.component.html',
})
export class NavigationPage1Component {
constructor(
private navController: NavController
) {}
ionViewDidEnter() {
if (count < 1) {
this.navController.navigateBack('/navigation/page2');
}
count++;
}
}

View File

@ -0,0 +1,3 @@
<p>
navigation-page2 works!
</p>

View File

@ -0,0 +1,17 @@
import { Component } from '@angular/core';
import { NavController } from '@ionic/angular';
@Component({
selector: 'app-navigation-page2',
templateUrl: './navigation-page2.component.html',
})
export class NavigationPage2Component {
constructor(
private navController: NavController
) {}
ionViewDidEnter() {
this.navController.navigateForward('/navigation/page1');
}
}

View File

@ -0,0 +1,3 @@
<p>
navigation-page3 works!
</p>

View File

@ -0,0 +1,16 @@
import { Component, OnInit } from '@angular/core';
import { NavController } from '@ionic/angular';
@Component({
selector: 'app-navigation-page3',
templateUrl: './navigation-page3.component.html',
})
export class NavigationPage3Component {
constructor(
private navController: NavController
) {}
ionViewDidEnter() {
this.navController.navigateRoot('/navigation/page2');
}
}

View File

@ -0,0 +1,7 @@
<ion-content>
<h1>Nested page 1</h1>
<p>
<ion-button routerLink="/tabs" id="goto-tabs">Go To Tabs</ion-button>
<ion-button routerLink="/nested-outlet/page2" id="goto-nested-page2">Go To SECOND</ion-button>
</p>
</ion-content>

View File

@ -0,0 +1,16 @@
import { Component, NgZone, OnDestroy, OnInit } from '@angular/core';
@Component({
selector: 'app-nested-outlet-page',
templateUrl: './nested-outlet-page.component.html',
})
export class NestedOutletPageComponent implements OnDestroy, OnInit {
ngOnInit() {
NgZone.assertInAngularZone();
}
ngOnDestroy() {
NgZone.assertInAngularZone();
}
}

View File

@ -0,0 +1,6 @@
<ion-content>
<h1>Nested page 2</h1>
<p>
<ion-button routerLink="/nested-outlet/page" id="goto-nested-page1">Go To FIRST</ion-button>
</p>
</ion-content>

View File

@ -0,0 +1,16 @@
import { Component, NgZone, OnDestroy, OnInit } from '@angular/core';
@Component({
selector: 'app-nested-outlet-page2',
templateUrl: './nested-outlet-page2.component.html',
})
export class NestedOutletPage2Component implements OnDestroy, OnInit {
ngOnInit() {
NgZone.assertInAngularZone();
}
ngOnDestroy() {
NgZone.assertInAngularZone();
}
}

View File

@ -0,0 +1,13 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>
NESTED OUTLET
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-router-outlet></ion-router-outlet>
</ion-content>

View File

@ -0,0 +1,9 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-nested-outlet',
templateUrl: './nested-outlet.component.html',
})
export class NestedOutletComponent {
}

View File

@ -0,0 +1 @@
export * from './popover-inline.module';

View File

@ -0,0 +1,14 @@
import { NgModule } from "@angular/core";
import { RouterModule } from "@angular/router";
import { PopoverInlineComponent } from "./popover-inline.component";
@NgModule({
imports: [RouterModule.forChild([
{
path: '',
component: PopoverInlineComponent
}
])],
exports: [RouterModule]
})
export class PopoverInlineRoutingModule { }

View File

@ -0,0 +1,13 @@
<ion-button (click)="openPopover(popover)">Open Popover</ion-button>
<ion-popover #popover>
<ng-template>
<ion-content>
<ion-list>
<ion-item *ngFor="let item of items">
<ion-label>{{ item }}</ion-label>
</ion-item>
</ion-list>
</ion-content>
</ng-template>
</ion-popover>

View File

@ -0,0 +1,24 @@
import { Component } from "@angular/core";
/**
* Validates that inline popovers will correctly display
* dynamic contents that are updated after the modal is
* display.
*/
@Component({
selector: 'app-popover-inline',
templateUrl: 'popover-inline.component.html'
})
export class PopoverInlineComponent {
items: string[] = [];
openPopover(popover: HTMLIonPopoverElement) {
popover.present();
setTimeout(() => {
this.items = ['A', 'B', 'C', 'D'];
}, 1000);
}
}

View File

@ -0,0 +1,11 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { IonicModule } from "@ionic/angular";
import { PopoverInlineRoutingModule } from "./popover-inline-routing.module";
import { PopoverInlineComponent } from "./popover-inline.component";
@NgModule({
imports: [CommonModule, IonicModule, PopoverInlineRoutingModule],
declarations: [PopoverInlineComponent],
})
export class PopoverInlineModule { }

View File

@ -0,0 +1,39 @@
<ion-header>
<ion-toolbar>
<ion-title>
Providers Test
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<p>
isLoaded: <span id="is-loaded">{{isLoaded}}</span>
</p>
<p>
isReady: <span id="is-ready">{{isReady}}</span>
</p>
<p>
isResumed: <span id="is-resumed">{{isResumed}}</span>
</p>
<p>
isPaused: <span id="is-paused">{{isPaused}}</span>
</p>
<p>
isResized: <span id="is-resized">{{isResized}}</span>
</p>
<p>
isTesting: <span id="is-testing">{{isTesting}}</span>
</p>
<p>
isDesktop: <span id="is-desktop">{{isDesktop}}</span>
</p>
<p>
isMobile: <span id="is-mobile">{{isMobile}}</span>
</p>
<p>
keyboardHeight: <span id="keyboard-height">{{keyboardHeight}}</span>
</p>
<p>
queryParams: <span id="query-params">{{queryParams}}</span>
</p>
</ion-content>

View File

@ -0,0 +1,85 @@
import { Component, NgZone } from '@angular/core';
import {
Platform, ModalController, AlertController, ActionSheetController,
PopoverController, ToastController, PickerController, MenuController,
LoadingController, NavController, DomController, Config
} from '@ionic/angular';
@Component({
selector: 'app-providers',
templateUrl: './providers.component.html',
})
export class ProvidersComponent {
isLoaded = false;
isReady = false;
isResumed = false;
isPaused = false;
isResized = false;
isTesting: boolean = undefined;
isDesktop: boolean = undefined;
isMobile: boolean = undefined;
keyboardHeight = 0;
queryParams = '';
constructor(
actionSheetCtrl: ActionSheetController,
alertCtrl: AlertController,
loadingCtrl: LoadingController,
menuCtrl: MenuController,
pickerCtrl: PickerController,
modalCtrl: ModalController,
platform: Platform,
popoverCtrl: PopoverController,
toastCtrl: ToastController,
navCtrl: NavController,
domCtrl: DomController,
config: Config,
zone: NgZone
) {
// test all providers load
if (
actionSheetCtrl && alertCtrl && loadingCtrl && menuCtrl && pickerCtrl &&
modalCtrl && platform && popoverCtrl && toastCtrl && navCtrl && domCtrl && config
) {
this.isLoaded = true;
}
// test platform ready()
platform.ready().then(() => {
NgZone.assertInAngularZone();
this.isReady = true;
});
platform.resume.subscribe(() => {
console.log('platform:resume');
NgZone.assertInAngularZone();
this.isResumed = true;
});
platform.pause.subscribe(() => {
console.log('platform:pause');
NgZone.assertInAngularZone();
this.isPaused = true;
});
platform.resize.subscribe(() => {
console.log('platform:resize');
NgZone.assertInAngularZone();
this.isResized = true;
});
const firstQuery = platform.getQueryParam('firstParam');
const secondQuery = platform.getQueryParam('secondParam');
this.queryParams = `firstParam: ${firstQuery}, firstParam: ${secondQuery}`;
this.isDesktop = platform.is('desktop');
this.isMobile = platform.is('mobile');
// test config
this.isTesting = config.getBoolean('_testing');
this.keyboardHeight = config.getNumber('keyboardHeight');
zone.runOutsideAngular(() => {
document.dispatchEvent(new CustomEvent('pause'));
document.dispatchEvent(new CustomEvent('resume'));
window.dispatchEvent(new CustomEvent('resize'));
});
}
}

View File

@ -0,0 +1,17 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>router-link page</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<p>ngOnInit: <span id="ngOnInit">{{onInit}}</span></p>
<p>canGoBack: <span id="canGoBack">{{canGoBack}}</span></p>
<p>ionViewWillEnter: <span id="ionViewWillEnter">{{willEnter}}</span></p>
<p>ionViewDidEnter: <span id="ionViewDidEnter">{{didEnter}}</span></p>
<p>ionViewWillLeave: <span id="ionViewWillLeave">{{willLeave}}</span></p>
<p>ionViewDidLeave: <span id="ionViewDidLeave">{{didLeave}}</span></p>
</ion-content>

View File

@ -0,0 +1,52 @@
import { Component, OnInit, NgZone } from '@angular/core';
import { IonRouterOutlet, ViewDidEnter, ViewDidLeave, ViewWillLeave } from '@ionic/angular';
@Component({
selector: 'app-router-link-page',
templateUrl: './router-link-page.component.html',
})
export class RouterLinkPageComponent implements OnInit, ViewWillLeave, ViewDidEnter, ViewWillLeave, ViewDidLeave {
onInit = 0;
willEnter = 0;
didEnter = 0;
willLeave = 0;
didLeave = 0;
canGoBack: boolean = null;
constructor(
private ionRouterOutlet: IonRouterOutlet
) {}
ngOnInit() {
NgZone.assertInAngularZone();
this.canGoBack = this.ionRouterOutlet.canGoBack();
this.onInit++;
}
ionViewWillEnter() {
if (this.onInit !== 1) {
throw new Error('ngOnInit was not called');
}
if (this.canGoBack !== this.ionRouterOutlet.canGoBack()) {
throw new Error('canGoBack() changed');
}
NgZone.assertInAngularZone();
this.willEnter++;
}
ionViewDidEnter() {
if (this.canGoBack !== this.ionRouterOutlet.canGoBack()) {
throw new Error('canGoBack() changed');
}
NgZone.assertInAngularZone();
this.didEnter++;
}
ionViewWillLeave() {
NgZone.assertInAngularZone();
this.willLeave++;
}
ionViewDidLeave() {
NgZone.assertInAngularZone();
this.didLeave++;
}
}

View File

@ -0,0 +1,12 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>Router Page 2</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<ion-button routerLink="/router-link-page3" id="goToPage3">Go to Page 3</ion-button>
</ion-content>

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-router-link-page2',
templateUrl: './router-link-page2.component.html'
})
export class RouterLinkPage2Component implements OnInit {
constructor() { }
ngOnInit() {
console.log('ngOnInit')
}
}

View File

@ -0,0 +1,12 @@
<ion-header>
<ion-toolbar color="dark">
<ion-buttons slot="start">
<ion-back-button defaultHref="/?token=ABC#fragment" id="goBackFromPage3"></ion-back-button>
</ion-buttons>
<ion-title>Router Page 3</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
Page 3
</ion-content>

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-router-link-page3',
templateUrl: './router-link-page3.component.html'
})
export class RouterLinkPage3Component implements OnInit {
constructor() { }
ngOnInit() {
console.log('ngOnInit')
}
}

View File

@ -0,0 +1,39 @@
<ion-header>
<ion-toolbar>
<ion-title>
Router Link Test
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<p>ngOnInit: <span id="ngOnInit">{{onInit}}</span></p>
<p>ionViewWillEnter: <span id="ionViewWillEnter">{{willEnter}}</span></p>
<p>ionViewDidEnter: <span id="ionViewDidEnter">{{didEnter}}</span></p>
<p>ionViewWillLeave: <span id="ionViewWillLeave">{{willLeave}}</span></p>
<p>ionViewDidLeave: <span id="ionViewDidLeave">{{didLeave}}</span></p>
<p>Change Detections: <span id="counter">{{counter()}}</span></p>
<p>
<ion-button routerLink="/router-link-page" expand="block" color="dark" id="routerLink">ion-button[routerLink]
</ion-button>
<ion-button routerLink="/router-link-page" routerDirection="root" expand="block" color="dark" id="routerLink-root">
ion-button[routerLink] (direction:root)</ion-button>
<ion-button routerLink="/router-link-page" routerDirection="back" expand="block" color="dark" id="routerLink-back">
ion-button[routerLink] (direction:back)</ion-button>
</p>
<p><a [routerLink]="null">null router link</a></p>
<p><a routerLink="/router-link-page" id="a">a[routerLink]</a></p>
<p><a routerLink="/router-link-page" routerDirection="root" id="a-root">a[routerLink] (direction:root)</a></p>
<p><a routerLink="/router-link-page" routerDirection="back" id="a-back">a[routerLink] (direction:back)</a></p>
<p><button (click)="navigate()" id="button">navigate</button></p>
<p><button (click)="navigateForward()" id="button-forward">navigateForward</button></p>
<p><button (click)="navigateRoot()" id="button-root">navigateForward</button></p>
<p><button (click)="navigateBack()" id="button-back">navigateBack</button></p>
<p><button id="queryParamsFragment" routerLink="/router-link-page2/MyPageID==" [queryParams]="{ token: 'A&=#Y' }"
fragment="myDiv1">Query Params and Fragment</button></p>
</ion-content>

View File

@ -0,0 +1,68 @@
import { Component, NgZone, OnInit } from '@angular/core';
import { NavController, ViewDidEnter, ViewDidLeave, ViewWillEnter, ViewWillLeave } from '@ionic/angular';
import { Router } from '@angular/router';
@Component({
selector: 'app-router-link',
templateUrl: './router-link.component.html',
})
export class RouterLinkComponent implements OnInit, ViewWillEnter, ViewDidEnter, ViewWillLeave, ViewDidLeave {
onInit = 0;
willEnter = 0;
didEnter = 0;
willLeave = 0;
didLeave = 0;
changes = 0;
constructor(
private navCtrl: NavController,
private router: Router
) {}
navigate() {
this.router.navigateByUrl('/router-link-page');
}
navigateForward() {
this.navCtrl.navigateForward('/router-link-page');
}
navigateBack() {
this.navCtrl.navigateBack('/router-link-page');
}
navigateRoot() {
this.navCtrl.navigateRoot('/router-link-page');
}
counter() {
this.changes++;
return Math.floor(this.changes / 2);
}
ngOnInit() {
NgZone.assertInAngularZone();
this.onInit++;
}
ionViewWillEnter() {
if (this.onInit !== 1) {
throw new Error('ngOnInit was not called');
}
NgZone.assertInAngularZone();
this.willEnter++;
}
ionViewDidEnter() {
NgZone.assertInAngularZone();
this.didEnter++;
}
ionViewWillLeave() {
NgZone.assertInAngularZone();
this.willLeave++;
}
ionViewDidLeave() {
NgZone.assertInAngularZone();
this.didLeave++;
}
}

View File

@ -0,0 +1,31 @@
<ion-header>
<ion-toolbar>
<ion-title>
Slides Test
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-slides pager="true" (ionSlideDidChange)="checkIndex()">
<ion-slide *ngFor="let text of slidesData">
<h1>{{text}}</h1>
</ion-slide>
</ion-slides>
<p>
index: <span id="slide-index">{{slideIndex}}</span>
index2: <span id="slide-index-2">{{slideIndex2}}</span>
</p>
<ion-button id="add-slides" (click)="addSlides()">
Add Slides
</ion-button>
<ion-button id="btn-prev" (click)="prevSlide()">
Prev Slide
</ion-button>
<ion-button id="btn-next" (click)="nextSlide()">
Next Slide
</ion-button>
</ion-content>

View File

@ -0,0 +1,40 @@
import { AfterViewInit, Component, ViewChild } from '@angular/core';
import { IonSlides } from '@ionic/angular';
@Component({
selector: 'app-slides',
templateUrl: './slides.component.html',
})
export class SlidesComponent implements AfterViewInit {
@ViewChild(IonSlides, { static: true }) slides: IonSlides;
slideIndex = 0;
slideIndex2 = 0;
slidesData = [];
constructor() { }
ngAfterViewInit() {
this.slides.ionSlideDidChange.subscribe(async () => {
this.slideIndex2 = await this.slides.getActiveIndex();
});
}
addSlides() {
const start = this.slidesData.length + 1;
this.slidesData.push(`Slide ${start}`, `Slide ${start + 1}`, `Slide ${start + 2}`);
}
prevSlide() {
this.slides.slidePrev();
}
nextSlide() {
this.slides.slideNext();
}
async checkIndex() {
this.slideIndex = await this.slides.getActiveIndex();
}
}

View File

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { TabsTab3Component } from './tabs-tab3/tabs-tab3.component';
import { TabsTab3NestedComponent } from './tabs-tab3-nested/tabs-tab3-nested.component';
const routes: Routes = [
{
path: '',
component: TabsTab3Component
},
{
path: 'nested',
component: TabsTab3NestedComponent
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class TabsLazyRoutingModule { }

View File

@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TabsLazyRoutingModule } from './tabs-lazy-routing.module';
import { TabsTab3Component } from './tabs-tab3/tabs-tab3.component';
import { IonicModule } from '@ionic/angular';
import { TabsTab3NestedComponent } from './tabs-tab3-nested/tabs-tab3-nested.component';
@NgModule({
declarations: [TabsTab3Component, TabsTab3NestedComponent],
imports: [
CommonModule,
IonicModule,
TabsLazyRoutingModule
]
})
export class TabsLazyModule { }

View File

@ -0,0 +1,15 @@
<ion-header>
<ion-toolbar>
<ion-title>Tab 3 - Page 2</ion-title>
<ion-buttons slot="start">
<ion-back-button defaultHref="/tabs/lazy"></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content class="ion-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/1" id="goto-tab1-page2">Go to Tab 1 - Page 2</ion-button>
</p>
</ion-content>

View File

@ -0,0 +1,7 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-tabs-tab3-nested',
templateUrl: './tabs-tab3-nested.component.html',
})
export class TabsTab3NestedComponent {}

View File

@ -0,0 +1,15 @@
<ion-header>
<ion-toolbar>
<ion-title>Tab 3 - Page 1</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<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/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>
</ion-content>

View File

@ -0,0 +1,7 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-tabs-tab3',
templateUrl: './tabs-tab3.component.html',
})
export class TabsTab3Component {}

View File

@ -0,0 +1,17 @@
<ion-header>
<ion-toolbar>
<ion-title>Tab 1 - Page 2 ({{id}})</ion-title>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<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>

View File

@ -0,0 +1,21 @@
import { ActivatedRoute } from '@angular/router';
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-tabs-tab1-nested',
templateUrl: './tabs-tab1-nested.component.html',
})
export class TabsTab1NestedComponent implements OnInit {
id = '';
constructor(
private route: ActivatedRoute,
) {}
ngOnInit() {
this.id = this.route.snapshot.paramMap.get('id');
}
next() {
return parseInt(this.id, 10) + 1;
}
}

View File

@ -0,0 +1,23 @@
<ion-header>
<ion-toolbar>
<ion-title>{{title}}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<h1>Welcome to Tab1</h1>
<ion-segment [(ngModel)]="segment" (ionChange)="segmentChanged($event)">
<ion-segment-button value="one">One</ion-segment-button>
<ion-segment-button value="two">Two</ion-segment-button>
</ion-segment>
<p>
Segment changed: <span class="segment-changed">{{changed}}</span>
</p>
<p>
<ion-button routerLink="/tabs/account/nested/1" id="goto-tab1-page2">Go to Page 2</ion-button>
<ion-button routerLink="/tabs/account/nested/1" [queryParams]="{search:'hello'}" fragment="fragment"
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>
</p>
</ion-content>

View File

@ -0,0 +1,24 @@
import { Component, NgZone } from '@angular/core';
@Component({
selector: 'app-tabs-tab1',
templateUrl: './tabs-tab1.component.html',
})
export class TabsTab1Component {
title = 'ERROR';
segment = 'one';
changed = 'false';
ionViewWillEnter() {
NgZone.assertInAngularZone();
setTimeout(() => {
NgZone.assertInAngularZone();
this.title = 'Tab 1 - Page 1';
});
}
segmentChanged(ev: any) {
console.log('Segment changed', ev);
this.changed = 'true';
}
}

View File

@ -0,0 +1,21 @@
<ion-header>
<ion-toolbar>
<ion-title>{{title}}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<h1>Welcome to Tab 2</h1>
<ion-segment [(ngModel)]="segment" (ionChange)="segmentChanged($event)">
<ion-segment-button value="one">One</ion-segment-button>
<ion-segment-button value="two">Two</ion-segment-button>
</ion-segment>
<p>
Segment changed: <span class="segment-changed">{{changed}}</span>
</p>
<p>
<ion-button routerLink="/tabs/account" id="goto-tab1-page1">Go to Tab 1 - Page 1</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>

View File

@ -0,0 +1,24 @@
import { Component, NgZone, OnInit } from '@angular/core';
@Component({
selector: 'app-tabs-tab2',
templateUrl: './tabs-tab2.component.html',
})
export class TabsTab2Component implements OnInit {
title = 'ERROR';
segment = 'two';
changed = 'false';
ngOnInit() {
NgZone.assertInAngularZone();
setTimeout(() => {
NgZone.assertInAngularZone();
this.title = 'Tab 2 - Page 1';
});
}
segmentChanged(ev: any) {
console.log('Segment changed', ev);
this.changed = 'true';
}
}

View File

@ -0,0 +1,5 @@
#test {
position: absolute;
bottom: 100px;
left: 0;
}

View File

@ -0,0 +1,46 @@
<ion-tabs (ionTabsDidChange)="tabChanged($event)" (ionTabsWillChange)="tabsWillChange($event)">
<ion-tab-bar>
<ion-tab-button tab="account">
<ion-label>Tab One</ion-label>
<ion-icon name="add"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="contact">
<ion-label>Tab Two</ion-label>
<ion-icon name="logo-ionic"></ion-icon>
</ion-tab-button>
<ion-tab-button tab="lazy">
<ion-label>Tab Three</ion-label>
<ion-icon name="save"></ion-icon>
</ion-tab-button>
</ion-tab-bar>
</ion-tabs>
<ion-fab horizontal="end" vertical="top">
<ion-fab-button id="tabs-state" style="width: 100px;">{{tabsDidChangeCounter}}.{{tabsDidChangeEvent}}</ion-fab-button>
</ion-fab>
<div id="test">
<ul>
<li>
ionTabsWillChange counter: <span id="ionTabsWillChangeCounter">{{ tabsWillChangeCounter }}</span>
</li>
<li>
ionTabsWillChange event: <span id="ionTabsWillChangeEvent">{{ tabsWillChangeEvent }}</span>
</li>
<li>
ionTabsWillChange selectedTab: <span id="ionTabsWillChangeSelectedTab">{{ tabsWillChangeSelectedTab }}</span>
</li>
</ul>
<ul>
<li>
ionTabsDidChange counter: <span id="ionTabsDidChangeCounter">{{ tabsDidChangeCounter }}</span>
</li>
<li>
ionTabsDidChange event: <span id="ionTabsDidChangeEvent">{{ tabsDidChangeEvent }}</span>
</li>
<li>
ionTabsDidChange selectedTab: <span id="ionTabsDidChangeSelectedTab">{{ tabsDidChangeSelectedTab }}</span>
</li>
</ul>
</div>

View File

@ -0,0 +1,33 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { IonTabBar } from '@ionic/angular';
@Component({
selector: 'app-tabs',
templateUrl: './tabs.component.html',
styleUrls: ['./tabs.component.css']
})
export class TabsComponent {
tabsDidChangeCounter = 0;
tabsDidChangeEvent = '';
tabsDidChangeSelectedTab = '';
tabsWillChangeCounter = 0;
tabsWillChangeEvent = '';
tabsWillChangeSelectedTab = '';
@ViewChild(IonTabBar) tabBar: IonTabBar;
tabChanged(ev: { tab: string }) {
console.log('ionTabsDidChange', this.tabBar.selectedTab);
this.tabsDidChangeCounter++;
this.tabsDidChangeEvent = ev.tab;
this.tabsDidChangeSelectedTab = this.tabBar.selectedTab;
}
tabsWillChange(ev: { tab: string }) {
console.log('ionTabsWillChange', this.tabBar.selectedTab);
this.tabsWillChangeCounter++;
this.tabsWillChangeEvent = ev.tab;
this.tabsWillChangeSelectedTab = this.tabBar.selectedTab;
}
}

View 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 {}

View 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: () => import('../tabs-lazy/tabs-lazy.module').then(m => m.TabsLazyModule)
}
]
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class TabsPageRoutingModule {}

View File

@ -0,0 +1,2 @@
export * from './version-test.component';
export * from './version-test.module';

View File

@ -0,0 +1,16 @@
import { NgModule } from "@angular/core";
import { RouterModule } from "@angular/router";
import { VersionTestComponent } from ".";
@NgModule({
imports: [
RouterModule.forChild([
{
path: '',
component: VersionTestComponent
}
])
],
exports: [RouterModule]
})
export class VersionTestRoutingModule { }

View File

@ -0,0 +1 @@
Version-specific tests

View File

@ -0,0 +1,8 @@
import { Component } from "@angular/core";
@Component({
selector: 'app-version-test',
templateUrl: 'version-test.component.html'
})
export class VersionTestComponent {
}

View File

@ -0,0 +1,12 @@
import { CommonModule } from "@angular/common";
import { NgModule } from "@angular/core";
import { IonicModule } from "@ionic/angular";
import { VersionTestRoutingModule } from "./version-test-routing.module";
import { VersionTestComponent } from "./version-test.component";
@NgModule({
imports: [CommonModule, IonicModule, VersionTestRoutingModule],
declarations: [VersionTestComponent],
exports: [VersionTestComponent]
})
export class VersionTestModule { }

View File

@ -0,0 +1,20 @@
<ion-header>
<ion-toolbar>
<ion-title>
ViewChild() test
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<ion-slides>
<ion-slide #slide>
<ion-button id="color-button">Hello! it's a button</ion-button>
<div #div id="tabs-result"></div>
<ion-tabs>
</ion-tabs>
</ion-slide>
<ion-slide>
<h1>Second slide</h1>
</ion-slide>
</ion-slides>
</ion-content>

View File

@ -0,0 +1,23 @@
import { Component, ViewChild, AfterViewInit, ElementRef } from '@angular/core';
import { IonTabs, IonButton, IonSlides, IonSlide } from '@ionic/angular';
@Component({
selector: 'app-view-child',
templateUrl: './view-child.component.html'
})
export class ViewChildComponent implements AfterViewInit {
@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);
this.button.color = 'danger';
if (loaded) {
this.div.nativeElement.textContent = 'all found';
}
}
}

View File

@ -0,0 +1,17 @@
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button></ion-back-button>
</ion-buttons>
<ion-title>virtual-scroll page</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<h1>Item {{itemNu}}</h1>
<p>ngOnInit: <span id="ngOnInit">{{onInit}}</span></p>
<p>ionViewWillEnter: <span id="ionViewWillEnter">{{willEnter}}</span></p>
<p>ionViewDidEnter: <span id="ionViewDidEnter">{{didEnter}}</span></p>
<p>ionViewWillLeave: <span id="ionViewWillLeave">{{willLeave}}</span></p>
<p>ionViewDidLeave: <span id="ionViewDidLeave">{{didLeave}}</span></p>
</ion-content>

View File

@ -0,0 +1,46 @@
import { Component, NgZone, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ViewDidEnter, ViewDidLeave, ViewWillEnter, ViewWillLeave } from '@ionic/angular';
@Component({
selector: 'app-virtual-scroll-detail',
templateUrl: './virtual-scroll-detail.component.html',
})
export class VirtualScrollDetailComponent implements OnInit, ViewWillEnter, ViewDidEnter, ViewWillLeave, ViewDidLeave {
onInit = 0;
willEnter = 0;
didEnter = 0;
willLeave = 0;
didLeave = 0;
itemNu = 'none';
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.itemNu = this.route.snapshot.paramMap.get('itemId');
NgZone.assertInAngularZone();
this.onInit++;
}
ionViewWillEnter() {
if (this.onInit !== 1) {
throw new Error('ngOnInit was not called');
}
NgZone.assertInAngularZone();
this.willEnter++;
}
ionViewDidEnter() {
NgZone.assertInAngularZone();
this.didEnter++;
}
ionViewWillLeave() {
NgZone.assertInAngularZone();
this.willLeave++;
}
ionViewDidLeave() {
NgZone.assertInAngularZone();
this.didLeave++;
}
}

View File

@ -0,0 +1,3 @@
<p>
[{{onInit}}] Item {{value}}
</p>

View File

@ -0,0 +1,17 @@
import { Component, OnInit, NgZone, Input } from '@angular/core';
@Component({
selector: 'app-virtual-scroll-inner',
templateUrl: './virtual-scroll-inner.component.html',
})
export class VirtualScrollInnerComponent implements OnInit {
@Input() value: string;
onInit = 0;
ngOnInit() {
NgZone.assertInAngularZone();
this.onInit++;
console.log('created');
}
}

View File

@ -0,0 +1,29 @@
<ion-header>
<ion-toolbar>
<ion-title>
Virtual Scroll Test
</ion-title>
<ion-buttons slot="end">
<ion-button (click)="addItems()">
<ion-icon name="add" slot="icon-only"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-virtual-scroll [items]="items" [headerFn]="myHeaderFn" [footerFn]="myFooterFn">
<ion-item-divider *virtualHeader="let header">{{ header }}</ion-item-divider>
<ion-item-divider *virtualFooter="let footer">-- {{ footer }}</ion-item-divider>
<!-- <ion-item *virtualItem="let item" itemHeight="itemHeight">
{{item.name}}
</ion-item> -->
<ion-item *virtualItem="let item" [routerLink]="['/', 'virtual-scroll-detail', item]">
<ion-label>
<app-virtual-scroll-inner [value]="item.name"></app-virtual-scroll-inner>
</ion-label>
<ion-icon *ngIf="(item.name % 2) === 0" name="airplane" slot="start"></ion-icon>
<ion-toggle slot="end" [(ngModel)]="item.checked"></ion-toggle>
</ion-item>
</ion-virtual-scroll>
</ion-content>

View File

@ -0,0 +1,36 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { HeaderFn } from '@ionic/core';
import { IonVirtualScroll } from '@ionic/angular';
@Component({
selector: 'app-virtual-scroll',
templateUrl: './virtual-scroll.component.html',
})
export class VirtualScrollComponent {
@ViewChild(IonVirtualScroll, { static: true }) virtualScroll: IonVirtualScroll;
items = Array.from({length: 100}, (_, i) => ({ name: `${i}`, checked: true}));
itemHeight = () => 44;
myHeaderFn: HeaderFn = (_, index) => {
if ((index % 10) === 0) {
return `Header ${index}`;
}
}
myFooterFn: HeaderFn = (_, index) => {
if ((index % 5) === 0) {
return `Footer ${index}`;
}
}
addItems() {
console.log('adding items');
this.items.push(
{ name: `New Item`, checked: true}
);
this.virtualScroll.checkEnd();
}
}

View File

View File

@ -0,0 +1,3 @@
export const environment = {
production: true
};

View File

@ -0,0 +1,16 @@
// This file can be replaced during build by using the `fileReplacements` array.
// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
export const environment = {
production: false
};
/*
* For easier debugging in development mode, you can import the following file
* to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
*
* This import should be commented out in production mode because it will have a negative impact
* on performance if an error is thrown.
*/
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>TestApp</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
</body>
</html>

View File

@ -0,0 +1,10 @@
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
export { AppServerModule } from './app/app.server.module';
export { renderModule, renderModuleFactory } from '@angular/platform-server';

View File

@ -0,0 +1,15 @@
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
document.addEventListener('DOMContentLoaded', () => {
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(err => console.error(err));
});

Some files were not shown because too many files have changed in this diff Show More