Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

angular 4+ assign @Input for ngComponentOutlet dynamically created component

Tags:

In Angular 4 to dynamically create a component you can use ngComponentOutlet directive: https://angular.io/docs/ts/latest/api/common/index/NgComponentOutlet-directive.html

something like this:

Dynamic component

@Component({
  selector: 'dynamic-component',
  template: `
     Dynamic component
  `
})
export class DynamicComponent {
  @Input() info: any;
}

App

@Component({
  selector: 'my-app',
  template: `
     App<br>
     <ng-container *ngComponentOutlet="component"></ng-container>
  `
})
export class AppComponent {
  this.component=DynamicComponent;
}

How do I pass @Input() info: any; information in this template <ng-container *ngComponentOutlet="component"></ng-container> ?

like image 748
Doua Beri Avatar asked Mar 01 '17 03:03

Doua Beri


People also ask

How to create components in angular dynamically?

In this article, we will learn how to create components in Angular dynamically. First, we need a component. For the simplicity, we are going to use a simple alert component that will take as Input the alert type. Next, If you think about it, eventually components are DOM elements so when you need to add an element, you need a place to “put” it.

What is the use of ngcomponentoutletngmodulefactory?

ngComponentOutletNgModuleFactory: Optional module factory to allow loading another module dynamically, then loading a component from that module. Syntax Simple <ng-container *ngComponentOutlet="componentTypeExpression"></ng-container>

How do I add a callback to ngcomponentoutlet?

make a callback that's called when the component is created, and inside that callback assign your @Input values and subscribe your @Output s manually. Now, ngComponentOutlet does not provide any callback functionality, so you may have to reinvent the wheel - create an ngComponentOutlet directive that supports callbacks.

What is the product component in angular?

The product component is an Angular Component that displays a list of Products defined as an array in the TypeScript file of the component. This component is going to be a parent component for this tutorial. Each product item reads data from the nested component. You can visit creating angular component .


2 Answers

Such a feature was discussed in the pull request for ngComponentOutlet but was dropped for now. Even the componentRef shown currently in https://angular.io/docs/ts/latest/api/common/index/NgComponentOutlet-directive.html is not public and therefore not available https://github.com/angular/angular/blob/3ef73c2b1945340ca6bd21f1790260c88698ae26/modules/%40angular/common/src/directives/ng_component_outlet.ts#L78

I'd suggest you create your own directive derived from https://github.com/angular/angular/blob/3ef73c2b1945340ca6bd21f1790260c88698ae26/modules/%40angular/common/src/directives/ng_component_outlet.ts#L72

and assign values to inputs like shown in Angular 2 dynamic tabs with user-click chosen components

this.compRef.instance.someProperty = 'someValue';
like image 64
Günter Zöchbauer Avatar answered Oct 20 '22 10:10

Günter Zöchbauer


With the help of the post of @Günter Zöchbauer I solved a similar problem this way - I hope you can adapt it somehow.

First I defined some interfaces:

// all dynamically loaded components should implement this guy
export interface IDynamicComponent { Context: object; }

// data from parent to dynLoadedComponent
export interface IDynamicComponentData {
  component: any;
  context?: object;
  caller?: any;
}

then I implemented them inside of the dynamically loaded component

dynamicLoadedComponentA.ts

// ...
export class DynamicLoadedComponentA implements IDynamicComponent {
// ...

// data from parent
public Context: object;

// ...

After that I built a new component which is responsible for the magic. Important here is that I had to register all dyn. loaded components as entryComponents.

dynamic.component.ts

@Component({
  selector: 'ngc-dynamic-component',
  template: ´<ng-template #dynamicContainer></ng-template>´,
  entryComponents: [ DynamicLoadedComponentA ]
})
export class DynamicComponent implements OnInit, OnDestroy, OnChanges {
  @ViewChild('dynamicContainer', { read: ViewContainerRef }) public dynamicContainer: ViewContainerRef;

  @Input() public componentData: IDynamicComponentData;

  private componentRef: ComponentRef<any>;
  private componentInstance: IDynamicComponent;

  constructor(private resolver: ComponentFactoryResolver) { }

  public ngOnInit() {
    this.createComponent();
  }

  public ngOnChanges(changes: SimpleChanges) {
    if (changes['componentData']) {
      this.createComponent();
    }
  }

  public ngOnDestroy() {
    if (this.componentInstance) {
      this.componentInstance = null;
    }
    if (this.componentRef) {
      this.componentRef.destroy();
    }
  }

  private createComponent() {
    this.dynamicContainer.clear();
    if (this.componentData && this.componentData.component) {
      const factory: ComponentFactory<any> = this.resolver.resolveComponentFactory(this.componentData.component);
      this.componentRef = this.dynamicContainer.createComponent(factory);
      this.componentInstance = this.componentRef.instance as IDynamicComponent;

      // fill context data
      Object.assign(this.componentInstance.Context, this.componentData.context || {});

      // register output events
      // this.componentRef.instance.outputTrigger.subscribe(event => console.log(event));
    }
  }
}

here the usage of this shiny new stuff:

app.html

<!-- [...] -->
<div>
  <ngc-dynamic-component [componentData]="_settingsData"></ngc-dynamic-component>
</div>
<!-- [...] -->

app.ts

// ...
  private _settingsData: IDynamicComponent = {
    component: DynamicLoadedComponentA,
    context: { SomeValue: 42 },
    caller: this
  };
// ...
like image 42
tobias-kutter Avatar answered Oct 20 '22 10:10

tobias-kutter