2

I used the following example Angular 2 Passing data to component when dynamically adding the component, and thanks to it I was able to see the value dataToPass (passed from parent to the dynamic created child) inside child component template, but I wasn't able to get the property inside child component costructor, in order to modify it.
Do you have an idea of how to do it?

You can see my plunk here and my code below:

//our root app component
import {
  NgModule, 
  Input, 
  ComponentRef, 
  Injectable, 
  Component, 
  Injector, 
  ViewContainerRef, 
  ViewChild, ComponentFactoryResolver} from "@angular/core";
import {BrowserModule} from '@angular/platform-browser'
import {Subject} from 'rxjs/Subject';

@Injectable()
export class SharedService {
  showModal:Subject<any> = new Subject();
}

@Component({
  selector: 'comp-comp',
  template: `MyComponent dataToPass: {{dataToPass}}, dataToPass2: {{dataToPass2}}`
})
export class CompComponent {
  dataToPass2;
  constructor() {
      this.dataToPass2 = this.dataToPass+' hello';
  }
}

@Component({
  selector: 'child-component',
  template: `
      <button (click)="showDialog()">show modal from child</button>
  `,
})
export class ChildComponent {
  constructor(private sharedService:SharedService) {}

  showDialog() {
    this.sharedService.showModal.next({'type': CompComponent, 'title': 'titolo2', 'dataToPass': 'dataToPass'});
  }

}

@Component({
  selector: 'modal-comp',
  template: `
  <div class="modal fade" id="theModal" tabindex="-1" role="dialog" aria-labelledby="theModalLabel">
    <div class="modal-dialog largeWidth" role="document">
      <div class="modal-content">
        <div class="modal-header">
          <h4 class="modal-title">{{theHeader}}</h4></div>
        <div class="modal-body" #theBody>
      </div>
    <div class="modal-footer">
    <button type="button" class="btn btn-default" data-dismiss="modal" (close)="close()">Close</button>
  </div></div></div></div>
`
})
export class ModalComponent {
  @ViewChild('theBody', {read: ViewContainerRef}) theBody;

  theHeader: string = '';
  dataToPass: string = '';
  cmpRefBody:ComponentRef<any>;

  constructor(
    sharedService:SharedService, 
    private componentFactoryResolver: ComponentFactoryResolver, 
    injector: Injector) {

    sharedService.showModal.subscribe(data => {
      if(this.cmpRef) {
        this.cmpRef.destroy();
      }
      let factory = this.componentFactoryResolver.resolveComponentFactory(data.type);
      this.cmpRef = this.theBody.createComponent(factory);
      this.cmpRef.instance.dataToPass = data.dataToPass;
      this.dataToPass = data.dataToPass;
      this.theHeader = data.title;
      console.log(data.title);
      console.log(data.dataToPass);
      $('#theModal').modal('show');
    });
  }

  close() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }
    this.cmpRef = null;
  }
}

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello</h2>
      <button (click)="showDialog()">show modal</button>
      <child-component></child-component>
    </div>
  `,
})
export class App {

  constructor(private sharedService:SharedService) {}

  showDialog() {
    this.sharedService.showModal.next({'type': CompComponent, 'title': 'titolo1', 'dataToPass': 'dataToPass'});
  }

}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App, ModalComponent, CompComponent, ChildComponent],
  providers: [SharedService],
  entryComponents: [CompComponent],
  bootstrap: [ App, ModalComponent ]
})
export class AppModule{}
Community
  • 1
  • 1
B. Ciervo
  • 135
  • 4
  • 16

2 Answers2

0

The constructor is executed when you create the component, this is before you assign the value. You can make it a setter to be able to execute code when a new value was passed:

export class CompComponent {
  private _dataToPass2;
  get dataToPass2() {
    return this._dataToPass2;
  }
  set dataToPass2(value) {
    this._dataToPass2 = value + 'hello';
  }
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    Oh I didn't know that you could you get and set that way. However, it gives me an error: EXCEPTION: Error in ./CompComponent class CompComponent - inline template:0:0 caused by: Maximum call stack size exceeded RangeError: Maximum call stack size exceeded at CompComponent.get [as dataToPass2] – B. Ciervo Jan 10 '17 at 09:09
  • Sorry, I was sloppy. The backing field needs a different name than the getter/setter - fixed. – Günter Zöchbauer Jan 10 '17 at 09:10
0

Thanks to Gunter suggestion, I was able to find the solution.

export class CompComponent {
  dataToPass2;

  ngAfterContentInit() {
    this.dataToPass2 = this.dataToPass + ' hello';
  }
}
B. Ciervo
  • 135
  • 4
  • 16