Using Angular 4.1.3, I'm working on a mapping application which lazy-loads various tool modules. Currently, there is a router-outlet, which places the tool within the map. However, I need to support placing the tool in a new tab, next to the map. The tab is dynamically created in response to loading the tool module, and there can be multiple tabs open simultaneously.
Creating a tab component is simple enough, and it seems like putting a dynamic component loader in the new tab (https://angular.io/docs/ts/latest/cookbook/dynamic-component-loader.html), is a reasonable way to place the tool in the tab. However, I have no idea how to actually get a reference to the tool's component for passing it to the loader, since it's part of a lazy-loaded module. Is there a way to have the router pass this to my app.component instead of outputting it via a router-outlet? I've thought about putting the router-outlet in a hidden div and then binding to it in the controller, but that seems hacky, and I'm not sure it would work.
Some similar questions/answers I've seen seemed to depend on SystemJS, but I'm using Webpack.
EDIT: I got a basic plunker running here: http://plnkr.co/edit/RPbyQZ4LyHN9o9ey2MJT?p=preview
The code there has a very basic component dynamically added to a tab
export class ContentPaneComponent implements OnInit {
@ViewChild('contentpane') el: ElementRef;
@Output() newContent: EventEmitter<any> = new EventEmitter();
private content: string;
private contentSubscription: Subscription;
private tab1 = new CompItem(htmlPaneComponent, {});
// private tab2 = new CompItem(LayerManagerComponent, {});
ngOnInit(): void {
}
}
the component which is specified in tab1 has to be included in the entrycomponents of content-pane.module entryComponents: [htmlPaneComponent]
Ultimately, I want to be creating new CompItem()
s when modules are lazy-loaded. When I activate a route such as:
{
path: 'search', loadChildren:
'components/conference-room-search/conference-room-search.module#ConferenceRoomSearchModule'
}
I think what I need is for the router to give me a reference to the module or its components.
Here's a strategy for dynamically and lazily loading a component. But please beware, I haven't tried it yet!
Get an NgModuleFactoryLoader
instance via dependency injection and asynchronously obtain the module containing the component you wish to lazily load. From that, obtain an NgModuleFactory
and then obtain an NgModuleRef
.
The NgModuleRef
will give you:
ComponentFactoryResolver
which accepts a Type<T>
(from @angular/core
)So you can't make a Type<T>
from your code to pass to the ComponentFactoryResolver
since your code can't depend on T
, but the module has access to the T
and can provide a Type<T>
.
Make the module implement an interface that can return a Type<any>
(the component class) and cast NgModuleRef.instance()
to that interface. Then use the ComponentFactoryResolver
. If that doesn't work for some reason, make the module call ComponentFactoryResolver
and return the component directly rather than a Type
. Once you have a ComponentFactory
you can do dynamic component loading like normal.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With