Angular 6 with ngComponentOutlet and data binding / updating

2.6k Views Asked by At

I read a lot about ngComponentOutlet not working with binding, but as far as i understood, all cases wanted something like child <--> parent binding/communication (@Input and @Output, and for that there is an ng-dynamic-component, which works). I think my case is a little bit simpler, i just want to make the binding get updated between the dynamically created components and it's own templates.

btw, I read these pages:

How to ngFor on multiple types of components using ngComponentOutlet?

https://github.com/angular/angular/issues/15360

Angular 2 dynamic tabs with user-click chosen components

Idea of ngfor and ngComponentOutlet based on first link, problem described in 2. & 3. link

Main idea: create a list, which contains different types, and render these differently based on their own templates. These templates contain bindings to their own components.

I put together a minimal example, but unfortunatelly i could not put this together in plunker, it did not work, so here are the main parts of the code.

Overview of the little example code: I have an empty array, and a button, and when i click this button, 2 components get created and inserted into the list. These components inside the list get rendered using their own custom template (e.g.: comp-a.component.html). This all works:

Toplevel html code:

<div>
  <div>
    <p>This is a static component, with working binding</p>
    <div [innerHtml]="staticBindingMemberValue"></div>
    <br>
    <hr>
  </div>
  <button type="button" (click)="onclick()">Generate dynamic data</button>
  <hr>
  <div *ngFor="let contentItem of arrayContent" style="border: solid 1px; padding: 20px;margin: 20px;">
    <ng-container *ngComponentOutlet="contentItem.component"></ng-container>
  </div>
</div>

Toplevel component code:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  arrayContent:any[] = [];

  staticBindingMemberValue:string = "Initial value for Static comp"

  onclick() {

    let a = new CompAComponent();
    let b = new CompBComponent();

    a.init("NEW value for A")
    b.init("NEW value for B")
    this.staticBindingMemberValue = "NEW value for Static comp"

    this.arrayContent.push(a)
    this.arrayContent.push(b)
  }
}

Example component 'A' (B is practically the same):

export class CompAComponent implements OnInit {

  component = CompAComponent;
  title:string = "Initial value for A"

  constructor() { }

  ngOnInit() {
  }

  init(newValue) {
    this.title = newValue
  }
}

The components own html template (could not be simpler):

<p [innerHtml]="title"></p>

As you can see, the 'title' member has an initial value, but in the click() method i call the 'init' methods on the components, and try to set a new value. The problem is, the data binding works, but it does not updates, so the list is rendered with the 'Initial value for A' string, and the newValue is simply set in the code behind, but the page not updates. Meanwhile, the update of the 'staticBindingMemberValue' works:

This is how it looks after clicking the button

I read many ways to instantiate components dynamically, i might misunderstand something, so my question is:

Is there still no way with Angular 6 to make this extremely simple dynamic component creation work?

How can i make this work, so when something happens waaaay after component creation (click method is called, some service gets data from server, etc...), the bindings get updated:

  • i should use another way to dynamically create components?

  • i should create databinding differently?

Thanks

[UPDATE]

Okay, I found a way to do this with factory resolver, but it is not the very same, and a little hackish.. any idea about this approach?

0

There are 0 best solutions below