Building Components on the Fly with Angular 5

I've been utilizing code similar to this to dynamically generate components within my application. These components need to support dynamic inputs. However, upon attempting to upgrade to Angular 5, I've encountered an issue with ReflectiveInjector being deprecated. If anyone has any insights on how to adapt this for use with Angular 5, I would greatly appreciate the assistance...

import {Component, Input, ViewContainerRef, ViewChild, ReflectiveInjector, ComponentFactoryResolver} from '@angular/core';
import {
  AComponent,
  BComponent,
  CComponent
} from './';

@Component({
  selector: 'dynamic-component',
  entryComponents: [
    AComponent,
    BComponent,
    CComponent
  ],
  template: `
    <div #dynamicComponentContainer></div>
  `
})
export class DynamicComponent {

  currentComponent = null;

  @ViewChild('dynamicPriceItemComponentContainer', { read: ViewContainerRef }) dynamicComponentContainer: ViewContainerRef;

  @Input() set componentData( data: { component: any, inputs: any }) {
    if (!data) {
      return;
    }

    let inputProviders = Object.keys(data.inputs).map((inputName) => {
      return { provide: inputName, useValue: data.inputs[inputName] };
    });

    let resolvedInputs = ReflectiveInjector.resolve(inputProviders);

    let injector = ReflectiveInjector.fromResolvedProviders(resolvedInputs, this.dynamicPriceItemComponentContainer.parentInjector);

    let factory = this.resolver.resolveComponentFactory(data.component);

    let component = factory.create(injector);

    this.dynamicComponentContainer.insert(component.hostView);

    if (this.currentComponent) {
      this.currentComponent.destroy();
    }

    this.currentComponent = component;
  }

  constructor(private resolver: ComponentFactoryResolver) {

  }
}

Answer №1

Perhaps this information will offer some insight.

constructor(private renderer: Renderer2,
            private viewContainerRef: ViewContainerRef,
            private componentFactoryResolver: ComponentFactoryResolver) {

}

private generateDynamicComponent(): void {
    const factory = this.componentFactoryResolver.resolveComponentFactory(MyComponent);
    const dynamicComponent = this.viewContainerRef.createComponent(factory);
    this.renderer.appendChild('element where you want append', dynamicComponent.location.nativeElement);
}

Answer №2

To implement the functionality, utilize Injector.create instead of ReflectiveInjector.

@Input()
set dynamicContent(dc: { component: any; attribute: any; payload: any }) {
  if (!dc) {
    return;
  }
  const injector = Injector.create({
    providers: [
      {
        provide: dc.attribute,
        useValue: dc.payload
      }
    ],
    parent: this.dynamicComponentContainer.parentInjector
  });
  const factory = this.resolver.resolveComponentFactory(dc.component);
  const component = factory.create(injector);
  this.dynamicComponentContainer.insert(component.hostView);
}

It is important to address the deprecation of Reflection when injecting input names into dynamic children components. The key is to refrain from injecting strings:

constructor(@Inject(LabelComponentAttributes) public ca: LabelComponentAttributes) {
  super();
  this.setCurrentStyles();
  this.setCurrentClasses();
}

Organize all inputs within a class and inject that class. Avoid grouping them in an interface as they are only accessible at runtime in TypeScript.

Cheers!

Answer №3

Future possibilities for achieving this include utilizing the NgComponentOutlet directive. You can refer to this discussion for more information. As an alternative in the meantime, consider exploring ng-dynamic-component.

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

Using TypeScript, you can utilize RxJS to generate a fresh Observable named "Array" from a static array

I've successfully created an observable from an array, but the issue is that its type shows as Observable<number> instead of Observable<number[]> getUsers(ids: string[]): Observable<number[]> { const arraySource = Observable.from ...

Error Arises When Making Selection in PrimeNG's P-ListBox Component

Whenever I choose an item from my listbox module, I encounter an error where the value is being returned as an object instead of an array in my listbox.js file from p-listbox by PrimeNG. HTML: <p-listbox formControlName="programType" [options]="phoneT ...

What are the guidelines for utilizing square brackets [ ] in directives like @Inputs?

I'm feeling a bit lost. Check out this straightforward directive: @Directive({ selector: '[myDirective]' }) export class MyDirective { private textContent: string; private isEnabled: boolean; @Input() myD ...

Creating a dynamic type class in TypeScript that can inherit characteristics from another class

Can a wrapper class be designed to dynamically inherit the properties of another class or interface? For instance... interface Person { readonly firstName: string; readonly lastName: string; readonly birthday?: Date } class Wrapper<T> { ...

Include a hash in the URL when the current location is entered into the view by scrolling

In my current situation, I am required to implement a @HostListener in order to navigate to an element within my web page: @HostListener('click', ['$event']) onClick(e: any) { e.preventDefault(); const href = e.target.getAttri ...

When you eliminate the Angular root element, what are the consequences that follow?

I am in the process of manually bootstrapping an Angular application. ngDoBootstrap(app) { app.bootstrap(AppComponent); } Each time the root element is removed from the DOM and re-injected, I bootstrap the application again. This cycle repeats multip ...

Using Typescript with Vue.js: Defining string array type for @Prop

How can I properly set the type attribute of the @Prop decorator to be Array<string>? Is it feasible? I can only seem to set it as Array without including string as shown below: <script lang="ts"> import { Component, Prop, Vue } from ...

What is the best method to retrieve the data received from a back-end system once an Upload request with form-data has been completed?

I've created an upload method to monitor the progress of file uploads. The upload process is successful, however, at the end, my backend server sends back an object (register) containing information about the uploaded file (such as ID). I'm unsu ...

How can I retrieve an array from an object containing both a property and an array in TypeScript?

One of my objects always consists of a property and an array. When I use the console.log(obj) method to print it out, it looks like the following example: ProjectName: MyTest1 [0] { foo: 1, bar: 2} [1] { foo: 3, bar: 4} [2] { foo: 5, bar: 6} Alternat ...

Aligning Description Item components horizontally in antdLearn how to easily horizontally align Description

Currently, I am utilizing the `antd` Description components. In this scenario, when there is no `title` for the items, the value should be aligned to the left. You can see an example of this alignment in the image below: https://i.sstatic.net/Ah70f.png I ...

Error in util.js: process variable is not defined in Angular 15

As I work on integrating the Voice JavaScript SDK into my Angular 15 application, I encountered an error after installing the necessary npm packages. When running the app, a reference error is displayed in the browser console and the UI fails to load. Unca ...

Is there a specific type that is narrower in scope when based on a string parameter?

tgmlDoc.createElement(tagName) typically returns objects of type any. I am looking to refine the return type in the function below in order to simplify the rest of my code. Is there a way to accomplish this? My attempt is shown below, but unfortunately, ...

Tips for converting the iterator from a v-for to a string within a v-if

I am seeking to comprehend how to utilize v-for with v-if's in order to generate repeated teasers without resorting to more simplistic vue-logic. Currently, it appears that when using v-for with v-if nested within, it is not feasible to assign the ind ...

Is it possible to host an Angular application on one port and a legacy application on another within a virtual machine?

I'm struggling to articulate this question properly, so please bear with me (or offer guidance) if I'm not doing it correctly. Here's the situation: In my Angular 4 app, the files are located on my host operating system (Ubuntu 16.04) and ...

The hidden pop-up window from a particular tool is currently not being displayed

I attempted to upload my code onto Stackblitz in search of assistance with my dynamic modal not displaying. I am working on a function that I intend to be able to call from any component to create a popup where I can dynamically modify the header, body, an ...

What's the best way to refactor the `await nextEvent(element, 'mousemove')` pattern in my code once it is no longer necessary?

Within my React component, the code includes the following: class MyComponent extends React.Component { // ... trackStats = false componentDidMount() { this.monitorActivity() } componentWillUnmount() { this.trackStat ...

Using promises in TypeScript index signature

Can you help me find the correct index signature for this particular class? class MyClass { [index: string]: Promise<void> | Promise<MyType>; // not working public async methodOne (): Promise<void> { ... } public async methodTwo () ...

What is the reason behind being unable to register two components with the same name using React Hook Form?

I have encountered an issue while using the useForm hook from React Hook Form library. Due to the specific UI library I am using, I had to create custom radio buttons. The problem arises when I try to register two components with the same name in the form ...

Error: Promises must be managed correctly

I've been working on a timer-based function that is supposed to run once a week and create almost identical copies of existing documents. However, every time I try to execute it, I encounter the error message "Promises must be handled appropriately." ...

Can ng-content be utilized within the app-root component?

I have successfully developed an Angular application, and now I am looking to integrate it with a content management system that generates static pages. In order to achieve this, I need to utilize content projection from the main index.html file. The desi ...