refactor(navigation): make the framework delegate more generic

This commit is contained in:
Dan Bucholtz
2017-12-07 12:06:02 -06:00
parent 02d34a26aa
commit 14a67e1ff5
12 changed files with 140 additions and 53 deletions

View File

@ -1,5 +1,8 @@
import { Directive, ElementRef, HostListener, Renderer2 } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import {
ControlValueAccessor,
NG_VALUE_ACCESSOR
} from '@angular/forms';
@Directive({
/* tslint:disable-next-line:directive-selector */

View File

@ -12,5 +12,4 @@ export interface AngularViewController extends PublicViewController {
componentRef?: ComponentRef<any>;
instance?: any;
angularHostElement?: HTMLElement;
}

View File

@ -14,9 +14,9 @@
}
},
"@stencil/core": {
"version": "0.0.8-10",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-0.0.8-10.tgz",
"integrity": "sha512-SfZt+0bFaicndqncbWwRIOD1bb4ds3YUjAEYBiouonI392WxKLKHIHo1l2ONgtqQLa8yKrR71ZUatbdfRIXyXw==",
"version": "0.0.8-12",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-0.0.8-12.tgz",
"integrity": "sha512-hVHl80opV8ZKa5dCyLZW0V+Fx8ePsTzIjZrQ94+bSsDvi6y3Eo4IK1CEsoG5CxfwZhQQyqE42miWkI9sRZRdsw==",
"dev": true,
"requires": {
"chokidar": "1.7.0",

View File

@ -1622,8 +1622,8 @@ declare global {
export interface IonModalAttributes extends HTMLAttributes {
mode?: string;
color?: string;
component?: string;
componentProps?: any;
component?: any;
data?: any;
cssClass?: string;
enableBackdropDismiss?: boolean;
modalId?: string;

View File

@ -62,8 +62,8 @@ export class Modal {
@Prop({ context: 'config' }) config: Config;
@Prop() mode: string;
@Prop() color: string;
@Prop() component: string;
@Prop() componentProps: any = {};
@Prop() component: any;
@Prop() data: any = {};
@Prop() cssClass: string;
@Prop() enableBackdropDismiss: boolean = true;
@ -161,15 +161,7 @@ export class Modal {
}
render() {
const ThisComponent = this.component;
let userCssClasses = 'ion-page';
if (this.cssClass) {
userCssClasses += ` ${this.cssClass}`;
}
const dialogClasses = createThemedClasses(this.mode, this.color, 'modal-wrapper');
return [
<div
onClick={this.backdropClick.bind(this)}
@ -182,11 +174,6 @@ export class Modal {
role='dialog'
class={dialogClasses}
>
<ThisComponent
{...this.componentProps}
class={userCssClasses}
>
</ThisComponent>
</div>
];
}
@ -194,8 +181,8 @@ export class Modal {
export interface ModalOptions {
component: string;
componentProps?: any;
component: any;
data?: any;
showBackdrop?: boolean;
enableBackdropDismiss?: boolean;
enterAnimation?: AnimationBuilder;

View File

@ -19,11 +19,6 @@ string
#### component
string
#### componentProps
any
@ -32,6 +27,11 @@ any
string
#### data
any
#### enableBackdropDismiss
boolean
@ -76,11 +76,6 @@ string
#### component
string
#### componentProps
any
@ -89,6 +84,11 @@ any
string
#### data
any
#### enableBackdropDismiss
boolean

View File

@ -1,18 +1,28 @@
import { FrameworkDelegate, Nav, ViewController } from '../../index';
import { FrameworkDelegate, FrameworkMountingData, } from '../../index';
import { isString } from '../../utils/helpers';
export class DomFrameworkDelegate implements FrameworkDelegate {
attachViewToDom(nav: Nav, enteringView: ViewController): Promise<any> {
attachViewToDom(parentElement: HTMLElement, tagOrElement: string | HTMLElement, classesToAdd: string[] = []): Promise<FrameworkMountingData> {
return new Promise((resolve) => {
const usersElement = document.createElement(enteringView.component) as HTMLElement;
usersElement.classList.add('ion-page');
enteringView.element = usersElement;
nav.element.appendChild(usersElement);
resolve();
const usersElement = (isString(tagOrElement) ? document.createElement(tagOrElement) : tagOrElement) as HTMLElement;
if (classesToAdd.length) {
for (const clazz of classesToAdd) {
usersElement.classList.add(clazz);
}
}
parentElement.appendChild(usersElement);
resolve({
element: usersElement
});
});
}
removeViewFromDom(nav: Nav, leavingView: ViewController): Promise<any> {
nav.element.removeChild(leavingView.element);
return Promise.resolve();
removeViewFromDom(parentElement: HTMLElement, childElement: HTMLElement): Promise<FrameworkMountingData> {
parentElement.removeChild(childElement);
return Promise.resolve({
element: null
});
}
}

View File

@ -6,11 +6,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<script src="/dist/ionic.js"></script>
</head>
<body>
<ion-nav-delegate></ion-nav-delegate>
<body onload="loadFirstPage()">
<ion-nav-controller></ion-nav-controller>
<ion-app>
<ion-nav root="page-one"></ion-nav>
<ion-nav></ion-nav>
</ion-app>
<style>
f {
@ -26,4 +25,87 @@
}
</style>
</body>
<script>
async function loadFirstPage() {
const nav = document.querySelector('ion-nav');
await nav.componentOnReady();
const firstPage = document.createElement('div');
firstPage.classList.add('first-page');
firstPage.innerHTML = `
<ion-header>
<ion-toolbar>
<ion-title>Page One</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<h1>Page One</h1>
<ion-button>Go to Page Two</ion-button>
</ion-content>
`;
await nav.push(firstPage);
// okay cool, we're in the DOM now
const button = firstPage.querySelector('ion-button');
button.addEventListener('click', async () => {
await goToPageTwo(nav);
});
}
async function goToPageTwo(nav) {
const secondPage = document.createElement('div');
secondPage.classList.add('second-page');
secondPage.innerHTML = `
<ion-header>
<ion-toolbar>
<ion-title>Page Two</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<h1>Page Two</h1>
<ion-button class="next">Go to Page Three</ion-button>
<ion-button class="previous">Go Back</ion-button>
</ion-content>
`;
// okay cool, we're in the DOM now
await nav.push(secondPage);
const previousButton = secondPage.querySelector('ion-button .previous');
previousButton.addEventListener('click', async () => {
await nav.pop();
});
const nextButton = secondPage.querySelector('ion-button .next');
nextButton.addEventListener('click', async () => {
await goToPageThree(nav);
});
}
async function goToPageThree(nav) {
const thirdPage = document.createElement('div');
thirdPage.classList.add('third-page');
thirdPage.innerHTML = `
<ion-header>
<ion-toolbar>
<ion-title>Page Three</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
<h1>Page Three</h1>
<ion-button class="previous">Go Back</ion-button>
</ion-content>
`;
// okay cool, we're in the DOM now
await nav.push(thirdPage);
const previousButton = thirdPage.querySelector('ion-button .previous');
previousButton.addEventListener('click', async () => {
await nav.pop();
});
}
</script>
</html>

View File

@ -446,7 +446,8 @@ export function fireViewWillLifecycles(enteringView: ViewController, leavingView
export function attachViewToDom(nav: Nav, enteringView: ViewController, delegate: FrameworkDelegate) {
if (enteringView && enteringView.state === STATE_NEW) {
return delegate.attachViewToDom(nav, enteringView).then(() => {
return delegate.attachViewToDom(nav.element, enteringView.component, ['ion-page']).then((mountingData) => {
Object.assign(enteringView, mountingData);
enteringView.state = STATE_ATTACHED;
});
}

View File

@ -6,8 +6,13 @@ import {
} from '../index';
export interface FrameworkDelegate {
attachViewToDom(navController: Nav, enteringView: ViewController): Promise<any>;
removeViewFromDom(navController: Nav, leavingView: ViewController): Promise<any>;
attachViewToDom(elementOrContainerToMountTo: any, elementOrComponentToMount: any, classesToAdd?: string[]): Promise<FrameworkMountingData>;
removeViewFromDom(elementOrContainerToUnmountFrom: any, elementOrComponentToUnmount: any): Promise<FrameworkMountingData>;
}
export interface FrameworkMountingData {
element: HTMLElement;
}
export interface NavContainer {

View File

@ -99,7 +99,7 @@ export function dismiss(navCtrl: any, dismissProxy: any, data?: any, role?: stri
export function destroy(viewController: ViewController, delegate?: FrameworkDelegate): Promise<any> {
assert(viewController.state !== STATE_DESTROYED, 'view state must be attached');
return delegate ? delegate.removeViewFromDom(viewController.nav, viewController) : Promise.resolve().then(() => {
return delegate ? delegate.removeViewFromDom(viewController.nav.element, viewController.element) : Promise.resolve().then(() => {
if (viewController.component) {
// TODO - consider removing classes and styles as thats what we do in ionic-angular

View File

@ -1,5 +1,5 @@
{
"name": "demo",
"name": "@ionic/angular-demo",
"version": "0.0.0",
"lockfileVersion": 1,
"requires": true,