Dynamic Angular component loading with lazy loading

In my Angular 4.1.3 project, I am currently developing a mapping application that incorporates lazy-loading for various tool modules. At present, the tools are loaded within the map using a router-outlet. However, I now need to expand this functionality to support opening the tool in a new tab alongside the map. These tabs must be dynamically created when loading the tool module and it should be possible to have multiple tabs open simultaneously.

While creating a tab component appears straightforward, the challenge lies in figuring out how to reference the tool's component so that it can be passed to the dynamic component loader for placement within the new tab. Since the tool is part of a lazy-loaded module, obtaining this reference is proving tricky. Is there a way for the router to pass this information to my app.component rather than outputting it through a router-outlet? One potential solution involves hiding the router-outlet within a div and binding to it in the controller, although this approach feels like a temporary workaround with uncertain results.

I've come across similar questions related to SystemJS, but my webpack setup presents different constraints.

UPDATE: I have managed to set up a basic plunker demonstration here: http://plnkr.co/edit/RPbyQZ4LyHN9o9ey2MJT?p=preview

The code in the plunker showcases a simple component being 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 specified component in tab1 must be included in the entry components of the content-pane.module as follows:

entryComponents: [htmlPaneComponent]

Ultimately, the goal is to generate new CompItem() instances upon lazily loading modules. When activating a route such as:

{
path: 'search', loadChildren:
'components/conference-room-search/conference-room-search.module#ConferenceRoomSearchModule'
    }

I believe the key requirement is for the router to provide a reference to either the module or its components.

Answer №1

Looking for a way to dynamically and lazily load a component? Here's a strategy to try out, but keep in mind that I have not tested it yet!

To start, acquire an instance of NgModuleFactoryLoader through dependency injection and asynchronously fetch the module that contains the component you want to lazily load. Once you have the module, retrieve the NgModuleFactory followed by obtaining an NgModuleRef.

The NgModuleRef will provide:

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

However, creating a Type<T> from your code to pass to the ComponentFactoryResolver may be challenging since your code cannot rely on T. Instead, the module has access to T and can supply a Type<T>.

To proceed, have the module implement an interface capable of returning a Type<any> (the component class) and cast NgModuleRef.instance() to that interface. Then make use of the ComponentFactoryResolver. If this approach encounters issues, have the module invoke ComponentFactoryResolver and directly return the component rather than a Type object. With a ComponentFactory at hand, perform dynamic component loading as usual.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error encountered while installing Material UI in Next.js with TypeScript and pure JavaScript configurations

I'm brand new to React and Next.js, so please forgive me for asking what may seem like a silly question. I'm attempting to install Material UI in a fresh Next.js application that I created using "npx create-next-app@latest". I've been refere ...

Top method for dynamically loading a specific component by using its selector as a variable

I'm currently in the process of developing a straightforward game using Angular. The game is structured to consist of multiple rounds, each with unique characteristics that are distinguished by the variable roundType. For instance, round types can in ...

Strategies for passing multiple props to a function in React using TypeScript, such as useState([]) and useState(boolean)

Dealing with API Structure { "default": [ { "id": 1, "name": "A" }, { "id": 2, "name": "B" }, { "id": 3, "name" ...

Using Angular components that have @Input properties in a module separate from where they are originally defined

There is a component with an @Input declared below: @Component({ selector: 'app-api-error-message', templateUrl: './api-error-message.component.html', styleUrls: ['./api-error-message.component.scss'], inputs: ['E ...

An obstacle encountered when implementing feature module services in a controller for a Nest JS microservice

Recently, I developed a feature module named "user" which includes a controller, model, and services to interact with my postgres database. Despite setting up everything correctly, I encountered an error when trying to call userService from the feature mod ...

The test function is not recognized by Cordova when the device is ready

Within my app.component.ts file, I have the following code snippet: export class AppComponent implements OnInit { constructor(private auth: AuthService, private fireBaseService: FirebaseService, ) {} ngOnInit() { this.auth.run(); document.addE ...

Exploring Angular2: A demonstration showcasing concurrent http requests (typeahead) using observables

Currently, I am working on several cases within my app that require the following sequence of events: Upon triggering an event, the desired actions are as follows: List item Check if the data related to that context is already cached; if so, serve cache ...

Creating Typescript packages that allow users to import the dist folder by using the package name

I am currently working on a TypeScript package that includes declarations to be imported and utilized by users. However, I have encountered an issue where upon publishing the package, it cannot be imported using the standard @scope/package-name format. I ...

What is the best way to dynamically load content on a page when the URL changes within the same angular component?

I'm attempting to have a page load specific content when the URL changes, all within the same component. myComponent.ts ngOnInit(){ this.router.events.subscribe(res=> { if (this.router.url.split('?')[0].split("/").pop() === &ap ...

Is there a specific typescript type that can be used for an SVG document that is embedded within an HTML object?

I need to embed an SVG object in my HTML code using the following syntax: <object id='mapObject' type="image/svg+xml" data="assets/maps/drawing.svg"> </object> After embedding the SVG object, I want to access it from my TypeScript c ...

Dealing with router parameters of an indefinite number in Angular 5: A comprehensive guide

Is there a method to efficiently handle an unknown number of router parameters in a recursive manner? For instance: We are dealing with product categories that may have subcategories, which can have their own subcategories and so on. There are a few key ...

Update AngularJS from version 1.2.6 to Angular 16 in order to resolve the Material issue

Currently, I am working on a project that involves upgrading AngularJS version 1.2.6 to Angular 16. However, I have encountered a significant challenge in understanding the variances between AngularJS material and Angular material. For example, in Angular ...

Generating a unique serial ID using Angular/JS

I am in the process of developing a function that will create a unique serial id by replacing a string with the format; xxxx-xxxx-xxxx-xxxx. The desired outcome is a serial like this: ABCD-1234-EFGH-5678, where the first and third parts consist of letters ...

Leveraging both the spread operator and optional fields can improve the productivity and readability of your

Imagine you have an object with a mandatory field that cannot be null: interface MyTypeMandatory { value: number; } Now, you want to update this object using fields from another object, but this time with an optional field: interface MyTypeOptional ...

Ways to determine the generic type of a property value from a decorated property within a decorator

While experimenting with some code, I encountered an issue where the generic type of a property value wasn't being resolved correctly when changing from TValue to (t: TValue) => TValue. Instead of being recognized as the expected number, it was now ...

Trigger a change event for a Material Checkbox by referencing its unique identifier

<div *ngFor="let cus of deselectedList | keyvalue" (click)="clickCheckBox('customer_'+cus.key+'_checkbox')"> {{cus.key}} <mat-checkbox id="customer_{{cus.key}}_checkbox" (change ...

The Vue Prop does not have an initializer and is not explicitly assigned in the constructor

Currently, I am utilizing props in Vue Class components. Within the constructor, I have defined the props without a value. This setup compiles and operates smoothly, except after the most recent VS Code / TSLint update, a warning message emerges: The pr ...

Chunk loading in IE 11 has encountered an error

Having an issue with my website which is created using Angular 5. It seems to be malfunctioning in IE 11, and I am encountering the following error in the console: https://i.stack.imgur.com/Ek895.png Any insights on why my Angular code isn't functio ...

Angular reactive forms are experiencing a setback where the value of '[value]' is not being properly set for controls

My scenario is as follows: <input #physicalAddress1 type="text" formControlName="PhysicalAddressLine1" /> <tfg-toggle #physicalAsPostal formControlName="PhysicalAsPostal" [onText]="'Yes'" [offText ...

Cypress: Conducting Test with Custom Timezone Setting on Windows

My testing environment was set up to run in UTC time zone. I utilized cy.clock() to initialize a date-time in UTC format, which the Web App will then display as the current browser date-time in UTC. In order to achieve this, I ensured TZ=UTC in my environ ...