21

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> ?

3
  • 2
    how do you send information to dynamically created component from template? Do you use @Input decorators or something else? Commented Mar 1, 2017 at 8:28
  • 1
    it depends what information, from where and what you mean by "from template". You'll need to provide more details if you want support. Commented Mar 1, 2017 at 8:29
  • @GünterZöchbauer I've updated the questions. Let me know if you need more info Commented Mar 1, 2017 at 8:40

3 Answers 3

10

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';
Sign up to request clarification or add additional context in comments.

8 Comments

Thanks. Is it possible to have a different ngComponentOutlet by the time v4.0 is released? I mean with some options that will deal with this problem?
I don't know about the plans. The conclusion was that supporting inputs is too complex for the first version and that they want to release it as is and then eventually approach that problem again, but I haven't seen related discussions since then (which doesn't mean much because I didn't have much time to check)
@GünterZöchbauer So, if I call a component dynamically with ngComponentOutlet the only way to send a model or data from my current template/component to the dynamic component is by creating a custom directive or using some kind of service right? ngComponentOutletdoesn't have any built in feature to communicate both components: the caller & the called? Not even ngComponentOutletInjector?
ngComponentOutletInjector is only to pass a customized injector. If you add a provider to your component where you use ngComponentOutletContainer you'll get the same result automatically for most use cases. I think they plan to support passing some context in Angular4. Not sure if this already landed.
@GünterZöchbauer Thanks! I will try the ngComponentOutletContainer + providers option. And I will also check thank link. My alternative is a service that updates the models in both sides, but I really preffer to leave that as last option.
|
7

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
  };
// ...

3 Comments

does this solution work with ahead of time compilation?
Currently, not tested with AOT, but I'll try test this in near future and complement my post.
the question was for ngComponentOutlet though. Without this directive, code getting too messy.
6

I think for now you can use

https://www.npmjs.com/package/ng-dynamic-component

It is made specifically for this issue

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.