mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 12:29:55 +08:00
feature(modal): support lazy loading of modal pages
This commit is contained in:
@ -5,6 +5,7 @@ import { NavParams } from '../../navigation/nav-params';
|
||||
import { NavOptions } from '../../navigation/nav-util';
|
||||
import { ViewController } from '../../navigation/view-controller';
|
||||
import { GestureController, BlockerDelegate, GESTURE_MENU_SWIPE, GESTURE_GO_BACK_SWIPE } from '../../gestures/gesture-controller';
|
||||
import { ModuleLoader } from '../../util/module-loader';
|
||||
import { assert } from '../../util/util';
|
||||
|
||||
/**
|
||||
@ -31,7 +32,9 @@ export class ModalCmp {
|
||||
public _renderer: Renderer,
|
||||
public _navParams: NavParams,
|
||||
public _viewCtrl: ViewController,
|
||||
gestureCtrl: GestureController
|
||||
gestureCtrl: GestureController,
|
||||
public moduleLoader: ModuleLoader
|
||||
|
||||
) {
|
||||
let opts = _navParams.get('opts');
|
||||
assert(opts, 'modal data must be valid');
|
||||
@ -49,7 +52,12 @@ export class ModalCmp {
|
||||
/** @private */
|
||||
_load(component: any) {
|
||||
if (component) {
|
||||
const componentFactory = this._cfr.resolveComponentFactory(component);
|
||||
|
||||
let cfr = this.moduleLoader.getComponentFactoryResolver(component);
|
||||
if (!cfr) {
|
||||
cfr = this._cfr;
|
||||
}
|
||||
const componentFactory = cfr.resolveComponentFactory(component);
|
||||
|
||||
// ******** DOM WRITE ****************
|
||||
const componentRef = this._viewport.createComponent(componentFactory, this._viewport.length, this._viewport.parentInjector, []);
|
||||
|
@ -4,6 +4,7 @@ import { App } from '../app/app';
|
||||
import { Config } from '../../config/config';
|
||||
import { Modal } from './modal';
|
||||
import { ModalOptions } from './modal-options';
|
||||
import { DeepLinker } from '../../navigation/deep-linker';
|
||||
|
||||
/**
|
||||
* @name ModalController
|
||||
@ -116,7 +117,7 @@ import { ModalOptions } from './modal-options';
|
||||
@Injectable()
|
||||
export class ModalController {
|
||||
|
||||
constructor(private _app: App, public config: Config) { }
|
||||
constructor(private _app: App, public config: Config, private deepLinker: DeepLinker) { }
|
||||
|
||||
/**
|
||||
* Create a modal to display. See below for options.
|
||||
@ -126,6 +127,6 @@ export class ModalController {
|
||||
* @param {object} opts Modal options
|
||||
*/
|
||||
create(component: any, data: any = {}, opts: ModalOptions = {}) {
|
||||
return new Modal(this._app, component, data, opts, this.config);
|
||||
return new Modal(this._app, component, data, opts, this.config, this.deepLinker);
|
||||
}
|
||||
}
|
69
src/components/modal/modal-impl.ts
Normal file
69
src/components/modal/modal-impl.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { App } from '../app/app';
|
||||
import { Config } from '../../config/config';
|
||||
import { isPresent } from '../../util/util';
|
||||
import { PORTAL_MODAL } from '../app/app-constants';
|
||||
import { ModalCmp } from './modal-component';
|
||||
import { ModalOptions } from './modal-options';
|
||||
import { ModalSlideIn, ModalSlideOut, ModalMDSlideIn, ModalMDSlideOut } from './modal-transitions';
|
||||
import { NavOptions } from '../../navigation/nav-util';
|
||||
import { ViewController } from '../../navigation/view-controller';
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export class ModalImpl extends ViewController {
|
||||
private _app: App;
|
||||
private _enterAnimation: string;
|
||||
private _leaveAnimation: string;
|
||||
|
||||
constructor(app: App, component: any, data: any, opts: ModalOptions = {}, config: Config) {
|
||||
data = data || {};
|
||||
data.component = component;
|
||||
opts.showBackdrop = isPresent(opts.showBackdrop) ? !!opts.showBackdrop : true;
|
||||
opts.enableBackdropDismiss = isPresent(opts.enableBackdropDismiss) ? !!opts.enableBackdropDismiss : true;
|
||||
data.opts = opts;
|
||||
|
||||
super(ModalCmp, data, null);
|
||||
this._app = app;
|
||||
this._enterAnimation = opts.enterAnimation;
|
||||
this._leaveAnimation = opts.leaveAnimation;
|
||||
|
||||
this.isOverlay = true;
|
||||
|
||||
config.setTransition('modal-slide-in', ModalSlideIn);
|
||||
config.setTransition('modal-slide-out', ModalSlideOut);
|
||||
config.setTransition('modal-md-slide-in', ModalMDSlideIn);
|
||||
config.setTransition('modal-md-slide-out', ModalMDSlideOut);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
getTransitionName(direction: string): string {
|
||||
let key: string;
|
||||
if (direction === 'back') {
|
||||
if (this._leaveAnimation) {
|
||||
return this._leaveAnimation;
|
||||
}
|
||||
key = 'modalLeave';
|
||||
} else {
|
||||
if (this._enterAnimation) {
|
||||
return this._enterAnimation;
|
||||
}
|
||||
key = 'modalEnter';
|
||||
}
|
||||
return this._nav && this._nav.config.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Present the action sheet instance.
|
||||
*
|
||||
* @param {NavOptions} [opts={}] Nav options to go with this transition.
|
||||
* @returns {Promise} Returns a promise which is resolved when the transition has completed.
|
||||
*/
|
||||
present(navOptions: NavOptions = {}) {
|
||||
navOptions.minClickBlockDuration = navOptions.minClickBlockDuration || 400;
|
||||
return this._app.present(this, navOptions, PORTAL_MODAL);
|
||||
}
|
||||
|
||||
}
|
@ -1,70 +1,25 @@
|
||||
import { App } from '../app/app';
|
||||
import { Config } from '../../config/config';
|
||||
import { isPresent } from '../../util/util';
|
||||
import { PORTAL_MODAL } from '../app/app-constants';
|
||||
import { ModalCmp } from './modal-component';
|
||||
import { ModalOptions } from './modal-options';
|
||||
import { ModalSlideIn, ModalSlideOut, ModalMDSlideIn, ModalMDSlideOut } from './modal-transitions';
|
||||
import { NavOptions } from '../../navigation/nav-util';
|
||||
import { ViewController } from '../../navigation/view-controller';
|
||||
|
||||
import { ModalOptions } from './modal-options';
|
||||
import { DeepLinker } from '../../navigation/deep-linker';
|
||||
|
||||
import { Overlay } from '../../navigation/overlay';
|
||||
import { OverlayProxy } from '../../navigation/overlay-proxy';
|
||||
import { ModalImpl } from './modal-impl';
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
export class Modal extends ViewController {
|
||||
private _app: App;
|
||||
private _enterAnimation: string;
|
||||
private _leaveAnimation: string;
|
||||
export class Modal extends OverlayProxy {
|
||||
|
||||
constructor(app: App, component: any, data: any, opts: ModalOptions = {}, config: Config) {
|
||||
data = data || {};
|
||||
data.component = component;
|
||||
opts.showBackdrop = isPresent(opts.showBackdrop) ? !!opts.showBackdrop : true;
|
||||
opts.enableBackdropDismiss = isPresent(opts.enableBackdropDismiss) ? !!opts.enableBackdropDismiss : true;
|
||||
data.opts = opts;
|
||||
public isOverlay: boolean = true;
|
||||
|
||||
super(ModalCmp, data, null);
|
||||
this._app = app;
|
||||
this._enterAnimation = opts.enterAnimation;
|
||||
this._leaveAnimation = opts.leaveAnimation;
|
||||
|
||||
this.isOverlay = true;
|
||||
|
||||
config.setTransition('modal-slide-in', ModalSlideIn);
|
||||
config.setTransition('modal-slide-out', ModalSlideOut);
|
||||
config.setTransition('modal-md-slide-in', ModalMDSlideIn);
|
||||
config.setTransition('modal-md-slide-out', ModalMDSlideOut);
|
||||
constructor(app: App, component: any, private data: any, private opts: ModalOptions = {}, config: Config, deepLinker: DeepLinker) {
|
||||
super(app, component, config, deepLinker);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
getTransitionName(direction: string): string {
|
||||
let key: string;
|
||||
if (direction === 'back') {
|
||||
if (this._leaveAnimation) {
|
||||
return this._leaveAnimation;
|
||||
}
|
||||
key = 'modalLeave';
|
||||
} else {
|
||||
if (this._enterAnimation) {
|
||||
return this._enterAnimation;
|
||||
}
|
||||
key = 'modalEnter';
|
||||
}
|
||||
return this._nav && this._nav.config.get(key);
|
||||
getImplementation(): Overlay {
|
||||
return new ModalImpl(this._app, this._component, this.data, this.opts, this._config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Present the action sheet instance.
|
||||
*
|
||||
* @param {NavOptions} [opts={}] Nav options to go with this transition.
|
||||
* @returns {Promise} Returns a promise which is resolved when the transition has completed.
|
||||
*/
|
||||
present(navOptions: NavOptions = {}) {
|
||||
navOptions.minClickBlockDuration = navOptions.minClickBlockDuration || 400;
|
||||
return this._app.present(this, navOptions, PORTAL_MODAL);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,19 +1,16 @@
|
||||
import { mockApp, mockConfig } from '../../../util/mock-providers';
|
||||
import { mockApp, mockConfig, mockDeepLinker } from '../../../util/mock-providers';
|
||||
import { Component } from '@angular/core';
|
||||
import { ModalController } from '../modal-controller';
|
||||
import { ModalCmp } from '../modal-component';
|
||||
import { ViewController } from '../../../navigation/view-controller';
|
||||
|
||||
describe('Modal', () => {
|
||||
|
||||
describe('create', () => {
|
||||
|
||||
it('should have the correct properties on modal view controller instance', () => {
|
||||
let modalCtrl = new ModalController(mockApp(), mockConfig());
|
||||
let modalViewController = modalCtrl.create(ComponentToPresent);
|
||||
expect(modalViewController.component).toEqual(ModalCmp);
|
||||
expect(modalViewController.isOverlay).toEqual(true);
|
||||
expect(modalViewController instanceof ViewController).toEqual(true);
|
||||
it('should have the correct properties on modal view controller proxy instance', () => {
|
||||
let modalCtrl = new ModalController(mockApp(), mockConfig(), mockDeepLinker());
|
||||
let modalViewControllerProxy = modalCtrl.create(ComponentToPresent);
|
||||
expect(modalViewControllerProxy._component).toEqual(ModalCmp);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -125,8 +125,6 @@ export class DeepLinker {
|
||||
_history: string[] = [];
|
||||
/** @internal */
|
||||
_indexAliasUrl: string;
|
||||
/** @internal */
|
||||
_cfrMap = new Map<any, ComponentFactoryResolver>();
|
||||
|
||||
|
||||
constructor(
|
||||
@ -277,12 +275,9 @@ export class DeepLinker {
|
||||
if (link.loadChildren) {
|
||||
// awesome, looks like we'll lazy load this component
|
||||
// using loadChildren as the URL to request
|
||||
return this._moduleLoader.load(link.loadChildren).then(loadedModule => {
|
||||
// kerpow!! we just lazy loaded a component!!
|
||||
// update the existing link with the loaded component
|
||||
link.component = loadedModule.component;
|
||||
this._cfrMap.set(link.component, loadedModule.componentFactoryResolver);
|
||||
return link.component;
|
||||
return this._moduleLoader.load(link.loadChildren).then((response) => {
|
||||
link.component = response.component;
|
||||
return response.component;
|
||||
});
|
||||
}
|
||||
|
||||
@ -294,7 +289,8 @@ export class DeepLinker {
|
||||
* @internal
|
||||
*/
|
||||
resolveComponent(component: any): ComponentFactory<any> {
|
||||
let cfr = this._cfrMap.get(component);
|
||||
|
||||
let cfr = this._moduleLoader.getComponentFactoryResolver(component);
|
||||
if (!cfr) {
|
||||
cfr = this._baseCfr;
|
||||
}
|
||||
|
77
src/navigation/overlay-proxy.ts
Normal file
77
src/navigation/overlay-proxy.ts
Normal file
@ -0,0 +1,77 @@
|
||||
import { App } from '../components/app/app';
|
||||
import { Config } from '../config/config';
|
||||
import { isString } from '../util/util';
|
||||
|
||||
|
||||
import { DeepLinker } from './deep-linker';
|
||||
import { NavOptions } from './nav-util';
|
||||
import { Overlay } from './overlay';
|
||||
|
||||
|
||||
export class OverlayProxy {
|
||||
|
||||
overlay: Overlay;
|
||||
_onWillDismiss: Function;
|
||||
_onDidDismiss: Function;
|
||||
|
||||
|
||||
constructor(public _app: App, public _component: any, public _config: Config, public _deepLinker: DeepLinker) {
|
||||
}
|
||||
|
||||
getImplementation(): Overlay {
|
||||
throw new Error('Child class must implement "getImplementation" method');
|
||||
}
|
||||
|
||||
/**
|
||||
* Present the modal instance.
|
||||
*
|
||||
* @param {NavOptions} [opts={}] Nav options to go with this transition.
|
||||
* @returns {Promise} Returns a promise which is resolved when the transition has completed.
|
||||
*/
|
||||
present(navOptions: NavOptions = {}) {
|
||||
// check if it's a lazy loaded component, or not
|
||||
const isLazyLoaded = isString(this._component);
|
||||
if (isLazyLoaded) {
|
||||
|
||||
return this._deepLinker.getComponentFromName(this._component).then((loadedComponent: any) => {
|
||||
this._component = loadedComponent;
|
||||
return this.createAndPresentOverlay(navOptions);
|
||||
});
|
||||
} else {
|
||||
return this.createAndPresentOverlay(navOptions);
|
||||
}
|
||||
}
|
||||
|
||||
dismiss(data?: any, role?: any, navOptions?: NavOptions): Promise<any> {
|
||||
if (this.overlay) {
|
||||
return this.overlay.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the current viewController has be successfully dismissed
|
||||
*/
|
||||
onDidDismiss(callback: Function) {
|
||||
this._onDidDismiss = callback;
|
||||
if (this.overlay) {
|
||||
this.overlay.onDidDismiss(this._onDidDismiss);
|
||||
}
|
||||
}
|
||||
|
||||
createAndPresentOverlay(navOptions: NavOptions) {
|
||||
this.overlay = this.getImplementation();
|
||||
this.overlay.onWillDismiss(this._onWillDismiss);
|
||||
this.overlay.onDidDismiss(this._onDidDismiss);
|
||||
return this.overlay.present(navOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the current viewController will be dismissed
|
||||
*/
|
||||
onWillDismiss(callback: Function) {
|
||||
this._onWillDismiss = callback;
|
||||
if (this.overlay) {
|
||||
this.overlay.onWillDismiss(this._onWillDismiss);
|
||||
}
|
||||
}
|
||||
}
|
8
src/navigation/overlay.ts
Normal file
8
src/navigation/overlay.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { NavOptions } from './nav-util';
|
||||
|
||||
export interface Overlay {
|
||||
present(opts?: NavOptions): Promise<any>;
|
||||
dismiss(data?: any, role?: any, navOptions?: NavOptions): Promise<any>;
|
||||
onDidDismiss(callback: Function): void;
|
||||
onWillDismiss(callback: Function): void;
|
||||
}
|
119
src/navigation/test/overlay-proxy.spec.ts
Normal file
119
src/navigation/test/overlay-proxy.spec.ts
Normal file
@ -0,0 +1,119 @@
|
||||
import { OverlayProxy } from '../overlay-proxy';
|
||||
|
||||
import { mockApp, mockConfig, mockDeepLinker, mockOverlay } from '../../util/mock-providers';
|
||||
|
||||
describe('Overlay Proxy', () => {
|
||||
describe('dismiss', () => {
|
||||
it('should call dismiss if overlay is loaded', (done: Function) => {
|
||||
|
||||
const instance = new OverlayProxy(mockApp(), 'my-component', mockConfig(), mockDeepLinker());
|
||||
instance.overlay = mockOverlay();
|
||||
spyOn(instance.overlay, instance.overlay.dismiss.name).and.returnValue(Promise.resolve());
|
||||
|
||||
const promise = instance.dismiss(null, null, null);
|
||||
|
||||
promise.then(() => {
|
||||
expect(instance.overlay.dismiss).toHaveBeenCalled();
|
||||
done();
|
||||
}).catch((err: Error) => {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('onWillDismiss', () => {
|
||||
it('should update the handler on the overlay object', () => {
|
||||
const instance = new OverlayProxy(mockApp(), 'my-component', mockConfig(), mockDeepLinker());
|
||||
instance.overlay = mockOverlay();
|
||||
spyOn(instance.overlay, instance.overlay.onWillDismiss.name);
|
||||
|
||||
const handler = () => { };
|
||||
instance.onWillDismiss(handler);
|
||||
|
||||
expect(instance.overlay.onWillDismiss).toHaveBeenCalledWith(handler);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onDidDismiss', () => {
|
||||
it('should update the handler on the overlay object', () => {
|
||||
const instance = new OverlayProxy(mockApp(), 'my-component', mockConfig(), mockDeepLinker());
|
||||
instance.overlay = mockOverlay();
|
||||
spyOn(instance.overlay, instance.overlay.onDidDismiss.name);
|
||||
|
||||
const handler = () => { };
|
||||
instance.onDidDismiss(handler);
|
||||
|
||||
expect(instance.overlay.onDidDismiss).toHaveBeenCalledWith(handler);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createAndPresentOverlay', () => {
|
||||
it('should set onWillDismiss and onDidDismiss handlers', (done: Function) => {
|
||||
const instance = new OverlayProxy(mockApp(), 'my-component', mockConfig(), mockDeepLinker());
|
||||
const handler = () => { };
|
||||
instance.onWillDismiss(handler);
|
||||
instance.onDidDismiss(handler);
|
||||
const knownOptions = {};
|
||||
const knownOverlay = mockOverlay();
|
||||
|
||||
spyOn(knownOverlay, knownOverlay.present.name).and.returnValue(Promise.resolve());
|
||||
spyOn(knownOverlay, knownOverlay.onDidDismiss.name);
|
||||
spyOn(knownOverlay, knownOverlay.onWillDismiss.name);
|
||||
spyOn(instance, 'getImplementation').and.returnValue(knownOverlay);
|
||||
|
||||
const promise = instance.createAndPresentOverlay(knownOptions);
|
||||
|
||||
promise.then(() => {
|
||||
expect(knownOverlay.present).toHaveBeenCalledWith(knownOptions);
|
||||
expect(knownOverlay.onDidDismiss).toHaveBeenCalledWith(handler);
|
||||
expect(knownOverlay.onWillDismiss).toHaveBeenCalledWith(handler);
|
||||
done();
|
||||
}).catch((err: Error) => {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('present', () => {
|
||||
it('should use present the overlay immediately if the component is not a string', (done: Function) => {
|
||||
const knownComponent = { };
|
||||
const deepLinker = mockDeepLinker();
|
||||
const knownOverlay = mockOverlay();
|
||||
const instance = new OverlayProxy(mockApp(), knownComponent, mockConfig(), deepLinker);
|
||||
const knownOptions = {};
|
||||
|
||||
spyOn(instance, 'getImplementation').and.returnValue(knownOverlay);
|
||||
spyOn(deepLinker, 'getComponentFromName');
|
||||
|
||||
const promise = instance.present(knownOptions);
|
||||
|
||||
promise.then(() => {
|
||||
expect(deepLinker.getComponentFromName).not.toHaveBeenCalled();
|
||||
done();
|
||||
}).catch((err: Error) => {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('should load the component if its a string before using it', (done: Function) => {
|
||||
const knownComponent = { };
|
||||
const deepLinker = mockDeepLinker();
|
||||
const knownOverlay = mockOverlay();
|
||||
const componentName = 'my-component';
|
||||
const instance = new OverlayProxy(mockApp(), componentName, mockConfig(), deepLinker);
|
||||
const knownOptions = {};
|
||||
|
||||
spyOn(instance, 'getImplementation').and.returnValue(knownOverlay);
|
||||
spyOn(deepLinker, 'getComponentFromName').and.returnValue(Promise.resolve(knownComponent));
|
||||
|
||||
const promise = instance.present(knownOptions);
|
||||
|
||||
promise.then(() => {
|
||||
expect(deepLinker.getComponentFromName).toHaveBeenCalledWith(componentName);
|
||||
done();
|
||||
}).catch((err: Error) => {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@ -12,6 +12,7 @@ import { Haptic } from '../tap-click/haptic';
|
||||
import { IonicApp } from '../components/app/app-root';
|
||||
import { Keyboard } from '../platform/keyboard';
|
||||
import { Menu } from '../components/menu/menu';
|
||||
import { NavOptions } from '../navigation/nav-util';
|
||||
import { NavControllerBase } from '../navigation/nav-controller-base';
|
||||
import { OverlayPortal } from '../components/nav/overlay-portal';
|
||||
import { PageTransition } from '../transitions/page-transition';
|
||||
@ -528,3 +529,12 @@ export function noop(): any { return 'noop'; };
|
||||
export function mockModuleLoader() {
|
||||
return { };
|
||||
}
|
||||
|
||||
export function mockOverlay() {
|
||||
return {
|
||||
present: (opts?: NavOptions) => { return Promise.resolve(); },
|
||||
dismiss: (data?: any, role?: any, navOptions?: NavOptions) => { return Promise.resolve(); },
|
||||
onDidDismiss: (callback: Function) => { },
|
||||
onWillDismiss: (callback: Function) => { }
|
||||
};
|
||||
}
|
@ -4,12 +4,17 @@ import { NgModuleLoader } from './ng-module-loader';
|
||||
|
||||
export const LAZY_LOADED_TOKEN = new OpaqueToken('LZYCMP');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
@Injectable()
|
||||
export class ModuleLoader {
|
||||
|
||||
/** @internal */
|
||||
_cfrMap = new Map<any, ComponentFactoryResolver>();
|
||||
|
||||
constructor(
|
||||
private _ngModuleLoader: NgModuleLoader,
|
||||
private _injector: Injector) {}
|
||||
@ -20,16 +25,23 @@ export class ModuleLoader {
|
||||
|
||||
const splitString = modulePath.split(SPLITTER);
|
||||
|
||||
return this._ngModuleLoader.load(splitString[0], splitString[1])
|
||||
.then(loadedModule => {
|
||||
console.timeEnd(`ModuleLoader, load: ${modulePath}'`);
|
||||
const ref = loadedModule.create(this._injector);
|
||||
return this._ngModuleLoader.load(splitString[0], splitString[1]).then(loadedModule => {
|
||||
console.timeEnd(`ModuleLoader, load: ${modulePath}'`);
|
||||
const ref = loadedModule.create(this._injector);
|
||||
|
||||
return {
|
||||
componentFactoryResolver: ref.componentFactoryResolver,
|
||||
component: ref.injector.get(LAZY_LOADED_TOKEN)
|
||||
};
|
||||
});
|
||||
const component = ref.injector.get(LAZY_LOADED_TOKEN);
|
||||
|
||||
this._cfrMap.set(component, ref.componentFactoryResolver);
|
||||
|
||||
return {
|
||||
componentFactoryResolver: ref.componentFactoryResolver,
|
||||
component: component
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
getComponentFactoryResolver(component: Type<any>) {
|
||||
return this._cfrMap.get(component);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user