How to dynamically add component to another component in service
Asked Answered
P

1

6

I would dynamically component to another component in the service , Firstly inside the service factory both components and I created the component with access to ViewContainer. But the component cannot be create !

Service :

@Injectable({
    providedIn: 'root'
})
export class ModalService {

    componentRef: ComponentRef<ModalTemplateComponent>;

    constructor(private _modalService: BsModalService,
                private resolver: ComponentFactoryResolver,
                private injector: Injector) {
    }

    open(componentType: any) {

        const contentFactory = this.resolver
            .resolveComponentFactory(componentType);

        const templateFactory = this.resolver
            .resolveComponentFactory(ModalTemplateComponent);

        const componentRef = templateFactory.create(this.injector);
        componentRef.instance.container.createComponent(contentFactory);

this._modalService.show(componentRef.componentType, {class: 'modal-lg', initialState: {data: {test:true}});

    }
}

Component :

    selector: 'lib-modal-template',
    template: `
        <h1>{{title}}</h1>
        <ng-container #container>
        </ng-container>
    `,
    styleUrls: ['./modal-template.component.css']
})
export class ModalTemplateComponent implements OnInit {

        title:string;
    @ViewChild('container', {read: ViewContainerRef, static: true}) container: ViewContainerRef;
}

example :

this._modalService.open(NewUserForm,...);

Prepared answered 3/9, 2019 at 3:41 Comment(0)
V
3

First, this line will create new instance of ModalTemplateComponent, instead of componentRef, so you are not working on same instance.

this._modalService.show(componentRef.componentType, {class: 'modal-lg', initialState: {data: {test:true}}});

I made some adjustment (using ngComponentOutlet), it will work as you expected:

ModalService

@Injectable({
  providedIn: 'root'
})
export class ModalService {

  constructor(private _modalService: BsModalService,
    private resolver: ComponentFactoryResolver,
    private injector: Injector) {
  }

  open(componentType: any) {

    const ref = this._modalService.show(ModalTemplateComponent, {class: 'modal-lg', initialState: {data: {test:true}}});

    (ref.content as ModalTemplateComponent).componentType = componentType;

  }

}

ModalTemplateComponent

@Component({
  selector: 'app-modal-template',
  template: `
  <h1>{{title}}</h1>
  <ng-container *ngComponentOutlet="componentType">
  </ng-container>
  `,
  styleUrls: ['./modal-template.component.css']
})
export class ModalTemplateComponent implements OnInit {
  title: string = 'modal-template';

  @Input() componentType: any;

  constructor() { }

  ngOnInit() {
  }

}

Online demo: https://stackblitz.com/edit/angular-1srnej?file=src%2Fapp%2Fmodal.service.ts

===============================

if you want to working with dynamic component instance, we can using following solution:

ModalTemplateComponent

@Component({
  selector: 'app-modal-template',
  template: `
  <h1>{{title}}</h1>
  <ng-container #container>
  </ng-container>
  `,
  styleUrls: ['./modal-template.component.css']
})
export class ModalTemplateComponent implements OnInit, OnDestroy {
  title: string = 'modal-template';
  component: any;
  componentRef: ComponentRef<any>;
  @Input() set componentType(c: any) {
    this.component = c;

    this.renderContent();
  }

  @ViewChild('container', {
    read: ViewContainerRef,
    static: true
  }) container: ViewContainerRef;

  constructor() { }

  ngOnInit() {
  }
  renderContent() {
    this.container.clear();
    const injector = this.container.injector;
    const cfr = injector.get(ComponentFactoryResolver);

    const componentFactory = cfr.resolveComponentFactory(this.component);

    const componentRef = this.container.createComponent<any>(componentFactory);

    componentRef.instance.content = 'content from ' + this.title;

    this.componentRef = componentRef;

  }
  ngOnDestroy() {
    if (this.componentRef) {
      this.componentRef.destroy();
    }
  }
}

AlertContentComponent

export class AlertContentComponent implements OnInit {
  @Input() content = '';
  constructor() { }

  ngOnInit() {
  }

}

Demo: https://stackblitz.com/edit/angular-ythykh?file=src%2Fapp%2Fmodal-template%2Fmodal-template.component.ts

Viridi answered 3/9, 2019 at 6:4 Comment(7)
Thanks, How to access the Template component formGroup in Alert Component ?Prepared
if you want to access it, you could dynamic rendering Alert Component instead of using ngComponentOutletViridi
Can you give an example ?Prepared
wait a minute, I'll create new example for youViridi
@Prepared updated stackblitz.com/edit/…Viridi
How can I hide Modal from Alert component ?Prepared
you can create new post, I'll try to ans later. regardsViridi

© 2022 - 2024 — McMap. All rights reserved.