Issue Encountered When Attempting to Reuse Component Loaded Dynamically

Recently, I developed a component that has the ability to load a child component dynamically with a template retrieved from the server. If you are interested in similar topics, check out this discussion here:

Compile dynamic HTML in Angular 4/5 - something similar to $compile in Angular JS

I want to be able to call this component from any part of my application. Its selector should work within a modal template without causing multiple reloads (I can't refresh the modal repeatedly). It should also function when invoked from a browser window (without simultaneously loading both the modal and browser).

@Component({
  selector: 'my-component',
  template: `<h2>The following content will be dynamically created and injected<h2>
          <div #vc></div>`
})
export class TaggedDescComponent {
  @ViewChild('vc', {read: ViewContainerRef}) vc: ViewContainerRef;

  private cmpRef: ComponentRef<any>;

  constructor(private compiler: Compiler,
              private injector: Injector,
              private moduleRef: NgModuleRef<any>,
              private backendService: backendService,
              ) {}

  ngAfterViewInit() {
    // Retrieve HTML content from the backend.
    this.backendService.getHTMLFromServer()
        .subscribe(rawHTML => this.createComponentFromRaw(rawHTML));
  }

  // Create the dynamic component here.
  private createComponentFromRaw(template: string) {
    // Assuming your template resembles `<h2><some-component [data]="data"></some-component>`
    // It includes an angular component `some-component` with injected data.

    // Now we define a new component. It utilizes the given template and can receive data input.
    const tmpCmp = Component({ template, styles })(class {
      // This anonymous class behaves like a standard angular class. You can incorporate @Inputs,
      // @Outputs, and inject dependencies.
      data: { some: 'data'};
      ngOnInit() { /* Add functionality to the dynamic component */}
    });

    // Generate a dynamic module as well.
    const tmpModule = NgModule({
      imports: [RouterModule],
      declarations: [tmpCmp],
      // providers: [] - Include necessary services if required by the dynamic component.
    })(class {});

    // Compile the module and component, then insert it into the #vc container within the current component template.
    this.compiler.compileModuleAndAllComponentsAsync(tmpModule)
      .then((factories) => {
        const f = factories.componentFactories[0];
        this.cmpRef = f.create(this.injector, [], null, this.moduleRef);
        this.cmpRef.instance.name = 'my-dynamic-component';
        this.vc.insert(this.cmpRef.hostView);
      });
  }

  // Implement cleanup operations. Additional clean-up procedures can be added here.
  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }
  }
}

However, when this section is reloaded (without refreshing the browser), I encounter the following error:

ERROR Error: Type e is part of the declarations of 2 modules: function(){} and function(){}! Please consider moving e to a higher module that imports function(){} and function(){}. You can also create a new NgModule that exports and includes e then import that NgModule in function(){} and function(){}.
    at le (main.js:1)
    at e._addTypeToModule (main.js:1)
    at main.js:1
    at Array.forEach (<anonymous>)
    at e.getNgModuleMetadata (main.js:1)
    at e._loadModules (main.js:1)
    at e._compileModuleAndAllComponents (main.js:1)
    at e.compileModuleAndAllComponentsAsync (main.js:1)
    at e.compileModuleAndAllComponentsAsync (main.js:1)
    at e.createComponentFromRaw (main.js:1)

Answer №1

When you need to render a component dynamically, it must be imported and registered in the parent module of the components.

If you try to use the same component in a different part of the application, there may be some issues that have workarounds available. You can refer to the following article for more information:

However, this process can become complex. I suggest using portals, which are a new feature in Angular CDK. Portals allow you to dynamically render a piece of UI into an open slot on the page. This UI can be a Component or a TemplateRef, and the open slot is a PortalHost.

There is also a helpful video presentation on this topic.

https://www.youtube.com/watch?v=YQMIR01dQew

I hope this information is useful! Best of luck!

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

Assign a value to ReplaySubject if it is currently devoid of any

I am facing a challenge with my ReplaySubject in the component after content initialization. Whenever it initializes, it always gets set to "/api/bulletin/getall" value and overrides any value assigned to it before in the onViewChanged function. How can ...

Guide to implementing a universal style for a disabled mat-form-field in Angular 16

Is it possible to change the color of disabled mat-form-field from the global configuration in Angular Material 16 by defining it at the root level? Creating a custom material theme and custom material typography involves: @use "@angular/material&quo ...

Having trouble with running npm start for the Angular2 QuickStart on Windows 10?

While attempting to replicate the Angular official tutorial for Windows 10 (https://angular.io/guide/quickstart), I encountered an error when running the "npm start" command: 0 info it worked if it ends with ok 1 verbose cli [ 'C:\\Program ...

Issue with Angular custom toggle functionality not functioning properly on mobile devices

I've been working on creating a custom toggle feature in Angular. While everything runs smoothly on desktop, I'm encountering issues on mobile devices. On desktop, the toggle works by clicking and dragging to the right, whereas on mobile, it shou ...

What is the method to access a component from a module that has been imported into the app module?

We are currently working on a project that has the following hierarchy. app/ ├── app.component.html ├── app.component.ts ├── app.module.ts <--moduleA and moduleB is imported here ├── app-routing.module.ts ├── moduleA/ ...

Tips on how to exclude one key from validation and ensure that all other keys have a non-empty value

Currently, I am learning about array functions in JavaScript and have come across a solution that involves using Object.fromEntries. However, the dilemma is that in my Angular project, I am constrained by an outdated ES version which cannot be updated due ...

Tips for including multiple plugins in a next.config.js

I am eager to introduce sass and BEM methodology into our company's project, but I am encountering some challenges with integrating the sass plugin into our existing codebase. Currently, we are utilizing typescript and CSS plugins. const path = requi ...

Using a universal class URL for all components in Angular 6: Tips and tricks

One common class is imported in all components with a common URL, but the URL appears to not be working. How can I create a common URL for all components in Angular so that changes need only be made in the common class in the future? export class CommonCl ...

What is the best method for confirming that a string is not undefined, null, or an empty string in an Angular template?

Is there an efficient method to verify whether a string is not undefined, null, or '' in an angular template? If the value is valid, then show this section. <div class="flex-row date-area" *ngIf="startDate !== undefined && startDate ...

Tips for displaying HTML content from a JSON web template

Currently, I am working with a JSON web template that consists of nested elements. My goal is to render HTML based on the content of this JSON web template. I attempted using ngx-schema-form, however my JSON does not contain properties variables. I also t ...

The inability to utilize custom images as icons with the "icon" property is a limitation for Android and IOS development in NativeScript

Having some trouble with the "icon" property in the Navigation button tag to use a custom image as an icon. On Android, it's working fine, but on iOS the image appears oversize. I've tried using scss and setting height in the tags themselves wit ...

Uncovering the Mutable Object Type within an Immutable Object

I would like to create a type that specifically extracts the mutable object type from an existing immutable object type like such: import * as Immutable from 'seamless-immutable' interface IObjType { field: string; } type TObjImmType = Immuta ...

Sorting the ids array has been modified in the ngrx updateOne

After loading an index of Invoices from an API into the NGRX Store, the user's input of a single Invoice triggers an update of the full details from the API. An issue arises with the order of the index changing when using Ngrx updateOne. The entity s ...

Deleting multiple rows in TypeORM with PostgreSQL and Node.js (using TypeScript)

Hey there, I'm looking for a way to efficiently erase rows in one go without having to run a loop. Can't seem to figure it out on my own, any assistance would be greatly appreciated. async remove(ids: DeleteEmployeeAnswerDTO): Promise<boolean& ...

Passing an event between components in AngularDart

Two components, componentA and componentB, are siblings within the structure of componentMother. When componentA is clicked, an event is triggered and handled by event handlerA. How can this event be passed to componentB and handled by event handler B? W ...

What is the best method to proceed to the following line in Angular once receiving a response from the HTTP client?

When the response is not received from const thumbnailSource = this.getThumbnailImage();, the next line will be executed. After receiving a response from getThumbnailImage(), the next line must be executed. constructor(private httpClient: HttpClient) {} ...

Unlocking new perspectives with a click

Currently exploring Angular development, I have encountered a question here but couldn't find the solution I was looking for. I am seeking suggestions and ideas on how to approach this issue. Essentially, my HTML includes buttons like the ones shown ...

Retrieve an item from an Angular 2 Observable Dataservice

I'm new to using Observables in Angular 2 and I have a query. In my data service class, there is a method called getExplorerPageData which sends an http request returning a data structure containing several arrays. I want to create another function n ...

Tips on avoiding tab selection in ngx-bootstrap

My current setup includes two tabs using ngx-bootstrap as shown below. I am looking to disable the tab functionality programmatically: <tabset> <tab heading="First">Tab 1 content</tab> <tab heading="Second">Tab 2 content< ...

best practices for choosing items from a dropdown menu using Angular

I have a dropdown list displaying existing tags/chips created by users in the past. However, I'm having an issue where when I select a tag from the dropdown list, it doesn't show up in my input field (similar to the Chart tag currently). I am abl ...