14

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.

4
  • Can you create a minimal example of what you're trying to achieve? Commented Jun 1, 2017 at 19:58
  • Okay, I finally got a very basic plunker made to demonstrate part of what I'm describing, at plnkr.co/edit/RPbyQZ4LyHN9o9ey2MJT?p=preview. This is basically a combination of the dynamic component loader shown here: angular.io/docs/ts/latest/cookbook/… and the tabs implementation from here: embed.plnkr.co/afhLA8wHw9LRnzwwTT3M . Commented Jun 2, 2017 at 18:23
  • Are you asking how you can get a reference to the component that was just dynamically loaded as part of your module (i.e. ConferenceRoomSearchModule) so that you can then use it in conjunction with your dynamic component loader? Commented Mar 1, 2018 at 20:59
  • I'd also like any advice on dynamically creating a component, and lazily deferring loading of the component's code until it needs to be dynamically created. Commented Jul 25, 2018 at 18:05

1 Answer 1

3

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:

  • a ComponentFactoryResolver which accepts a Type<T> (from @angular/core)
  • instance() of the module class.

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.