mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
fix(angular): modal and popover support
This commit is contained in:
@@ -13,6 +13,7 @@ export { VirtualHeader } from './directives/virtual-header';
|
||||
export { VirtualFooter } from './directives/virtual-footer';
|
||||
|
||||
/* Providers */
|
||||
export { AngularDelegate } from './providers/angular-delegate';
|
||||
export { ActionSheetController } from './providers/action-sheet-controller';
|
||||
export { AlertController } from './providers/alert-controller';
|
||||
export { Events } from './providers/events';
|
||||
|
||||
@@ -25,6 +25,7 @@ import { VirtualHeader } from './directives/virtual-header';
|
||||
import { VirtualFooter } from './directives/virtual-footer';
|
||||
|
||||
/* Providers */
|
||||
import { AngularDelegate } from './providers/angular-delegate';
|
||||
import { ActionSheetController } from './providers/action-sheet-controller';
|
||||
import { AlertController } from './providers/alert-controller';
|
||||
import { Events, setupProvideEvents } from './providers/events';
|
||||
@@ -71,10 +72,6 @@ import { ToastController } from './providers/toast-controller';
|
||||
imports: [
|
||||
CommonModule,
|
||||
],
|
||||
providers: [
|
||||
ModalController,
|
||||
PopoverController,
|
||||
],
|
||||
schemas: [
|
||||
CUSTOM_ELEMENTS_SCHEMA
|
||||
]
|
||||
@@ -84,6 +81,9 @@ export class IonicAngularModule {
|
||||
return {
|
||||
ngModule: IonicAngularModule,
|
||||
providers: [
|
||||
ModalController,
|
||||
PopoverController,
|
||||
AngularDelegate,
|
||||
AlertController,
|
||||
ActionSheetController,
|
||||
Events,
|
||||
|
||||
52
angular/src/providers/angular-delegate.ts
Normal file
52
angular/src/providers/angular-delegate.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import {
|
||||
ApplicationRef,
|
||||
ComponentFactoryResolver,
|
||||
Injectable,
|
||||
Injector,
|
||||
} from '@angular/core';
|
||||
|
||||
import { FrameworkDelegate } from '@ionic/core';
|
||||
|
||||
|
||||
@Injectable()
|
||||
export class AngularDelegate implements FrameworkDelegate {
|
||||
|
||||
private elRefMap = new WeakMap<HTMLElement, any>();
|
||||
|
||||
constructor(
|
||||
private cfr: ComponentFactoryResolver,
|
||||
private injector: Injector,
|
||||
private appRef: ApplicationRef
|
||||
) {}
|
||||
|
||||
attachViewToDom(container: any, component: any, data?: any, cssClasses?: string[]): Promise<any> {
|
||||
|
||||
const componentFactory = this.cfr.resolveComponentFactory(component);
|
||||
const hostElement = document.createElement(componentFactory.selector);
|
||||
if (data) {
|
||||
Object.assign(hostElement, data);
|
||||
}
|
||||
|
||||
const childInjector = Injector.create([], this.injector);
|
||||
const componentRef = componentFactory.create(childInjector, [], hostElement);
|
||||
for (const clazz of cssClasses) {
|
||||
hostElement.classList.add(clazz);
|
||||
}
|
||||
|
||||
container.appendChild(hostElement);
|
||||
|
||||
this.appRef.attachView(componentRef.hostView);
|
||||
this.elRefMap.set(hostElement, componentRef);
|
||||
return Promise.resolve(hostElement);
|
||||
}
|
||||
|
||||
removeViewFromDom(_container: any, component: any): Promise<void> {
|
||||
const mountingData = this.elRefMap.get(component);
|
||||
if (mountingData) {
|
||||
mountingData.componentRef.destroy();
|
||||
this.elRefMap.delete(component);
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ModalOptions } from '@ionic/core';
|
||||
import { OverlayBaseController } from '../util/overlay';
|
||||
import { AngularDelegate } from '..';
|
||||
|
||||
@Injectable()
|
||||
export class ModalController extends OverlayBaseController<ModalOptions, HTMLIonModalElement> {
|
||||
constructor() {
|
||||
constructor(
|
||||
private angularDelegate: AngularDelegate,
|
||||
) {
|
||||
super('ion-modal-controller');
|
||||
}
|
||||
|
||||
create(opts?: ModalOptions): Promise<HTMLIonModalElement> {
|
||||
return super.create({
|
||||
...opts,
|
||||
delegate: this.angularDelegate
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export class Modal implements OverlayInterface {
|
||||
@Prop({ context: 'config' }) config: Config;
|
||||
|
||||
@Prop() overlayId: number;
|
||||
@Prop({ mutable: true }) delegate: FrameworkDelegate;
|
||||
@Prop() delegate: FrameworkDelegate;
|
||||
|
||||
/**
|
||||
* The color to use from your Sass `$colors` map.
|
||||
@@ -175,7 +175,7 @@ export class Modal implements OverlayInterface {
|
||||
...getClassMap(this.cssClass),
|
||||
'ion-page': true
|
||||
};
|
||||
return attachComponent(container, this.component, classes, data)
|
||||
return attachComponent(this.delegate, container, this.component, classes, data)
|
||||
.then(el => this.usersElement = el)
|
||||
.then(() => present(this, 'modalEnter', iosEnterAnimation, mdEnterAnimation, undefined));
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export class Popover implements OverlayInterface {
|
||||
|
||||
@Prop({ connect: 'ion-animation-controller' }) animationCtrl: HTMLIonAnimationControllerElement;
|
||||
@Prop({ context: 'config' }) config: Config;
|
||||
@Prop({ mutable: true }) delegate: FrameworkDelegate;
|
||||
@Prop() delegate: FrameworkDelegate;
|
||||
@Prop() overlayId: number;
|
||||
|
||||
/**
|
||||
@@ -185,7 +185,7 @@ export class Popover implements OverlayInterface {
|
||||
...getClassMap(this.cssClass),
|
||||
'popover-viewport': true
|
||||
};
|
||||
return attachComponent(container, this.component, classes, data)
|
||||
return attachComponent(this.delegate, container, this.component, classes, data)
|
||||
.then(el => this.usersElement = el)
|
||||
.then(() => present(this, 'popoverEnter', iosEnterAnimation, mdEnterAnimation, this.ev));
|
||||
}
|
||||
|
||||
2
core/src/index.d.ts
vendored
2
core/src/index.d.ts
vendored
@@ -109,7 +109,7 @@ export { PlatformConfig } from './global/platform-configs';
|
||||
export * from './components';
|
||||
|
||||
export { DomController, RafCallback } from './global/dom-controller';
|
||||
export { FrameworkDelegate, FrameworkMountingData } from './utils/dom-framework-delegate';
|
||||
export { FrameworkDelegate } from './utils/dom-framework-delegate';
|
||||
export { OverlayEventDetail } from './utils/overlays';
|
||||
|
||||
export interface Config {
|
||||
|
||||
@@ -1,41 +1,5 @@
|
||||
|
||||
export interface FrameworkDelegate {
|
||||
attachViewToDom(elementOrContainerToMountTo: any, elementOrComponentToMount: any, propsOrDataObj?: any, classesToAdd?: string[], escapeHatch?: any): Promise<FrameworkMountingData>;
|
||||
removeViewFromDom(elementOrContainerToUnmountFrom: any, elementOrComponentToUnmount: any, escapeHatch?: any): Promise<void>;
|
||||
}
|
||||
|
||||
|
||||
export interface FrameworkMountingData {
|
||||
element: HTMLElement;
|
||||
component: any;
|
||||
data: any;
|
||||
}
|
||||
|
||||
export class DomFrameworkDelegate implements FrameworkDelegate {
|
||||
|
||||
attachViewToDom(parentElement: HTMLElement, tagOrElement: string | HTMLElement, data: any = {}, classesToAdd: string[] = []): Promise<FrameworkMountingData> {
|
||||
return new Promise((resolve) => {
|
||||
const usersElement = (typeof tagOrElement === 'string' ? document.createElement(tagOrElement) : tagOrElement);
|
||||
Object.assign(usersElement, data);
|
||||
|
||||
if (classesToAdd.length) {
|
||||
for (const clazz of classesToAdd) {
|
||||
usersElement.classList.add(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
parentElement.appendChild(usersElement);
|
||||
|
||||
resolve({
|
||||
element: usersElement,
|
||||
data: data,
|
||||
component: tagOrElement
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
removeViewFromDom(parentElement: HTMLElement, childElement: HTMLElement): Promise<void> {
|
||||
parentElement.removeChild(childElement);
|
||||
return Promise.resolve();
|
||||
}
|
||||
attachViewToDom(container: any, component: any, propsOrDataObj?: any, cssClasses?: string[]): Promise<any>;
|
||||
removeViewFromDom(container: any, component: any): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { EventEmitter } from '@stencil/core';
|
||||
import { Animation, AnimationBuilder, Config, CssClassMap } from '..';
|
||||
import { Animation, AnimationBuilder, Config, CssClassMap, FrameworkDelegate } from '..';
|
||||
|
||||
let lastId = 1;
|
||||
|
||||
@@ -137,7 +137,10 @@ export function autoFocus(containerEl: HTMLElement): HTMLElement|null {
|
||||
return null;
|
||||
}
|
||||
|
||||
export function attachComponent(container: Element, component: string|HTMLElement, cssClasses: CssClassMap, data: any): Promise<HTMLElement> {
|
||||
export function attachComponent(delegate: FrameworkDelegate, container: Element, component: string|HTMLElement, cssClasses: CssClassMap, data: any): Promise<HTMLElement> {
|
||||
if (delegate) {
|
||||
return delegate.attachViewToDom(container, component, data, Object.keys(cssClasses));
|
||||
}
|
||||
const el = (typeof component === 'string') ? document.createElement(component) : component;
|
||||
Object.assign(el, data);
|
||||
Object.keys(cssClasses).forEach(c => el.classList.add(c));
|
||||
|
||||
Reference in New Issue
Block a user