maxrow
maxrow

Reputation: 71

Angular 2 Passing data to component when dynamically adding the component

I have dynamically added a component on the click of a button .

Below is the code for my widget . Simple div with color property being set as input.

Widget.tmpl.html

 div class="{{color}}" (click)="ChangeColor()"

In the Widget component i am taking color as my input . This component works fine when i add it manually . But now i am trying to dynamically add the component and also need to pass the Color Value to the Widget Component.

Below is the code in the app.component.ts where i am calling addItem() on the button click .

app.component.ts

export class AppComponent  {
  @ViewChild('placeholder', {read: ViewContainerRef}) viewContainerRef;
  private componentFactory: ComponentFactory<any>;

  constructor(componentFactoryResolver: ComponentFactoryResolver, compiler: Compiler) {
    this.componentFactory = componentFactoryResolver.resolveComponentFactory(MyAppComponent);

  }

  addItem () {
   this.viewContainerRef.createComponent(this.componentFactory, 0);
  }

 public  myValue:string = 'red';

 onChange(val: any) { this.myValue = val; } }

In the addItem() method i am dynamically adding my widget component to my view. The component gets added fine . But the problem is how to pass the color property when dynamically adding . Based on what color i pass when creating the widget i want it to be displayed in red or green etc. How to property bind in this scenario?

Here is some of the Code :

export class MyAppComponent { 

    @Input() color; 
    @Output('changes') result: EventEmitter<any> = new EventEmitter(); 

    public constructor() { 
    }

    ChangeColor() {
        this.ToggleColor();
        this.result.emit(this.color);// Emitting the color to the parent.        
    }

    ToggleColor() {
        if (this.color == "red")
            this.color = "blue";
        else
            this.color = "red";
    }
}

In the above code i am emitting my color to the parent app.component.ts but since i have dynamically added the widget component , i dont know where to add this code (changes)="onChange($event)". I tried to add this code in the div as shown below :

<div class="{{color}}" (click)="ChangeColor()" (changes)="onChange($event)"></div>

But it does not work.

Upvotes: 7

Views: 14057

Answers (3)

Oleg Bondarenko
Oleg Bondarenko

Reputation: 1820

I have faced with the same issue: component processes input data and creates own appearance based on this data. The only one issue was adding component as regular one with html template (and predefined input data) and dynamically with componentFactory and setting data after ngInit angular event. It broke all initialization component logic due to triggering ngInit event before setting input data for component. One possible solution might be adding flexible component initialization based on allow initialization flag, that is set before adding this component and after settings input data.

 initComponentData() {
        const canInitData = !this.appService.deniedInitData.value;
        if (canInitData) {
            this.initData();
        } else {

            this.subscriptions.push(
                this.appService.deniedInitData.pipe(filter(x => !x),take(1)).subscribe(() => {
                    this.initData();
                }));
        }
    }

appService - Injectable angular service with

deniedInitData: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);

Place when we are dynamically adding component:

this.appService.deniedInitData.next(true);
const cmpRef = this.viewContainerRef.createComponent(this.componentFactory, 0);

const instance = cmpRef.instance;
instance.someProp = 'someValue';                    
this.appService.deniedInitData.next(false);

Upvotes: 0

Alejandro
Alejandro

Reputation: 122

I will put this article if you can't find it in google https://netbasal.com/dynamically-creating-components-with-angular-a7346f4a982d It explains perfectly how to pass data, It helps me a lot to understand the resolveComponentFactory, Sorry for the answer is more like a comment but I do not have enough reputation.

Upvotes: 0

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657068

var cmpRef = this.viewContainerRef.createComponent(this.componentFactory, 0);
cmpRef.instance.someProp = 'someValue';
cmpRef.instance.someObservable.subscribe(val => this.someProp = val);

Upvotes: 15

Related Questions