Files
ionic-framework/angular/src/providers/angular-delegate.ts
2018-08-01 18:32:20 +02:00

136 lines
3.6 KiB
TypeScript

import { ApplicationRef, ComponentFactoryResolver, Injectable, InjectionToken, Injector, NgZone, ViewContainerRef } from '@angular/core';
import { FrameworkDelegate, ViewLifecycle } from '@ionic/core';
import { NavParams } from '../directives/navigation/nav-params';
@Injectable()
export class AngularDelegate {
constructor(
private zone: NgZone,
private appRef: ApplicationRef
) {}
create(
resolver: ComponentFactoryResolver,
injector: Injector,
location?: ViewContainerRef,
) {
return new AngularFrameworkDelegate(resolver, injector, location, this.appRef, this.zone);
}
}
export class AngularFrameworkDelegate implements FrameworkDelegate {
private elRefMap = new WeakMap<HTMLElement, any>();
constructor(
private resolver: ComponentFactoryResolver,
private injector: Injector,
private location: ViewContainerRef | undefined,
private appRef: ApplicationRef,
private zone: NgZone,
) {}
attachViewToDom(container: any, component: any, params?: any, cssClasses?: string[]): Promise<any> {
return new Promise(resolve => {
this.zone.run(() => {
const el = attachView(
this.resolver, this.injector, this.location, this.appRef, this.elRefMap,
container, component, params, cssClasses
);
resolve(el);
});
});
}
removeViewFromDom(_container: any, component: any): Promise<void> {
return new Promise(resolve => {
this.zone.run(() => {
const componentRef = this.elRefMap.get(component);
if (componentRef) {
componentRef.destroy();
this.elRefMap.delete(component);
}
resolve();
});
});
}
}
export function attachView(
resolver: ComponentFactoryResolver,
injector: Injector,
location: ViewContainerRef | undefined,
appRef: ApplicationRef,
elRefMap: WeakMap<HTMLElement, any>,
container: any, component: any, params: any, cssClasses: string[] | undefined
) {
const factory = resolver.resolveComponentFactory(component);
const childInjector = Injector.create({
providers: getProviders(params),
parent: injector
});
const componentRef = (location)
? location.createComponent(factory, location.length, childInjector)
: factory.create(childInjector);
const instance = componentRef.instance;
const hostElement = componentRef.location.nativeElement;
if (params) {
Object.assign(instance, params);
}
if (cssClasses) {
for (const clazz of cssClasses) {
hostElement.classList.add(clazz);
}
}
bindLifecycleEvents(instance, hostElement);
container.appendChild(hostElement);
if (!location) {
appRef.attachView(componentRef.hostView);
}
componentRef.changeDetectorRef.reattach();
elRefMap.set(hostElement, componentRef);
return hostElement;
}
const LIFECYCLES = [
ViewLifecycle.WillEnter,
ViewLifecycle.DidEnter,
ViewLifecycle.WillLeave,
ViewLifecycle.DidLeave,
ViewLifecycle.WillUnload
];
export function bindLifecycleEvents(instance: any, element: HTMLElement) {
LIFECYCLES.forEach(eventName => {
element.addEventListener(eventName, (ev: any) => {
if (typeof instance[eventName] === 'function') {
instance[eventName](ev.detail);
}
});
});
}
const NavParamsToken = new InjectionToken<any>('NavParamsToken');
function getProviders(params: {[key: string]: any}) {
return [
{
provide: NavParamsToken, useValue: params
},
{
provide: NavParams, useFactory: provideNavParamsInjectable, deps: [NavParamsToken]
}
];
}
function provideNavParamsInjectable(params: {[key: string]: any}) {
return new NavParams(params);
}