Динамическое создание компонента внутри модального компонента - Angular 4 - PullRequest
0 голосов
/ 22 мая 2018

Я создаю свой собственный модальный компонент, пока он идет хорошо, я могу динамически создать сам мой исходный модальный компонент, но затем я пытаюсь создать другой компонент внутри модального компонента.

С моим кодом нижедля компонента модального контейнера у меня есть viewCotainerRef для переменной шаблона, которая затем создает компонент внутри этого контейнера div.Моя проблема возникает тогда, когда я пытаюсь визуализировать DynamicContentComponent внутри ModalComponent. Я не могу получить viewContainerRef при первом щелчке, поскольку он undefined, однако при втором щелчке по модальному триггеру он определен.

Таким образом, я устанавливаю свой 'viewContainerRef' на DynamicContentComponent, когда генерируется ModalComponent.Отправка его в службу рендеринга, когда я ясно вижу, что консоль нормально выходит из системы.Но когда я прихожу для рендеринга фактического DynamicContentComponent с использованием того же viewContainerRef, оно не определено.

Извините, если это немного сбивает с толку, код приведен ниже, но если этого недостаточно, я опубликую на plunkr после работы.

Спасибо

ModalComponentService

@Injectable()
export class ModalService {
  public showModal: Subject<any> = new Subject();
  public viewContainerRef: ViewContainerRef;
  public injector: Injector;
  private resolver: ComponentFactoryResolver;
  private compiler: Compiler;
  private render: RenderService;

  constructor(resolver: ComponentFactoryResolver, compiler: Compiler, renderer: RenderService) {
    this.render = renderer;
    this.resolver = resolver;
    this.compiler = compiler;
  }

  public setViewContainerRef(vcRef: ViewContainerRef): void {
    this.viewContainerRef = vcRef;
  }

  public setInjector(injector: Injector): void {
    this.injector = injector;
  }

  public createDialog(module: any, component: any, paramsModal?: Object, paramsComponent?: Object) {

    const componentRef$ = new ReplaySubject();

    this.compiler.compileModuleAndAllComponentsAsync(module).then((data) => {
      const standardModalFactory = data.componentFactories.filter( (singleComponents) => {
        return singleComponents.componentType === StandardModalComponent;
      })[0];

      const modalRef = this.viewContainerRef.createComponent(standardModalFactory);

      modalRef.instance['destroy'] = () => {
        modalRef.destroy();
      };

      Object.assign(modalRef.instance, paramsModal);

      componentRef$.next(modalRef);
      componentRef$.complete();
    });

    this.render.renderComponent(module, component, paramsComponent).subscribe((data) => {
      console.log(data); 
    });

    return componentRef$;
  }
}

ModalComponent

export class ModalComponent implements OnInit {
  @ViewChild('modalPlaceholder', {read: ViewContainerRef}) container;

  @Output()
  public appModalCloseModal: EventEmitter<any> = new EventEmitter<void>();

  public showModal = true;
  private modalService: ModalService;
  public injector: Injector;

  constructor(modalService: ModalService, injector: Injector) {
    this.modalService = modalService;
    this.injector = injector;
  }

  public ngOnInit(): void {
    this.modalService.setViewContainerRef(this.container);
    this.modalService.setInjector(this.injector);
  }
}

Шаблон ModalComponent

<div #modalPlaceholder class="appModal-placeholer"></div>

StandardModalComponent - который вводится вконтейнер выше

export class StandardModalComponent extends StandardModal implements OnInit {
  @ViewChild('standardModalContent')
  public standardModalContent;

  @Input()
  public appStandardModalHeaderLabel: string;

  private renderService: RenderService;

  constructor(render: RenderService) {
    super();
    this.renderService = render;
  }

  ngOnInit() {
    this.renderService.setModalReference(this.standardModalContent);
  }
}

На Init выше это где он устанавливает 2-й viewContainerRef для компонента контента.

StandardModalComponent - Template

Так что это гдеКомпонент, который должен отображаться в модальном компоненте, будет вставлен в ссылку standardModalComponent

<div class="appStandardModal-container">
  <div class="appStandardModal-overlay">
    <div class="appStandardModal-modalDialog">

      <div class="appStandardModal-header">
        <div class="appStandardModal-titleContainer">
          <h3>{{appStandardModalHeaderLabel}}</h3>
        </div>

        <div class="appStandardModal-closeModal">
          <button (click)="closeModal()">
            <fa name="times"></fa>
          </button>
        </div>
      </div>

      <div #standardModalContent class="appStandardModal-content">

      </div>

    </div>
  </div>
</div>

И это мой RenderService для динамического создания нужного компонента внутри ссылки #standardModalContent.

@Injectable()
export class RenderService {
  public viewContainer: ViewContainerRef;
  public injectors: Injector;
  private compiler: Compiler;
  public modalComponentReference$: ReplaySubject<any>;

  constructor(compiler: Compiler) {
    this.compiler = compiler;
  }

  public setModalReference(viewContainer: ViewContainerRef): void {
    this.viewContainer = viewContainer;
    console.log('setModalReference', this.viewContainer);
  }

  public setModalInjectorReference(injector: Injector): void {
    this.injectors = injector;
  }

  public renderComponent(module: any, component: any, componentParams?: Object) {
    this.modalComponentReference$ = new ReplaySubject();
    console.log('setModalReference in render component', this.viewContainer);

    const factory = component.componentFactory;
    const createdComponent = this.viewContainer.createComponent(factory);

    Object.assign(createdComponent.instance, componentParams);

    this.modalComponentReference$.next(createdComponent);

    return this.modalComponentReference$;
  }

} 

Когда service.setModalReference первоначально вызывается на standardModalComponent, он нормально выходит из системы, однако, когда я вызываю метод renderComponent, он не определен при первом щелчке модального триггера, однакопосле каждого щелчка мышью.

Вероятно, бесполезно, но дает представление о том, что происходит, вот триггер щелчка для моего компонента ниже

OpenModalComponent

export class OrderedNamesComponent implements IOrderedNames, OnInit {
  @Input()
  public appOrderedNamesName: boolean;

  @Input()
  public appOrderedNamesIndex: number;

  private modalService: ModalService;
  private params: { appStandardModalHeaderLabel: string; onSave: () => void };

  constructor(modalService: ModalService) {
    this.modalService = modalService;
  }

  public ngOnInit(): void {
    this.setParams();
  }

  public emitToParent() {
    this.modalService.createDialog(AppModule, TestComponentComponent, this.params);
  }

  private setParams(): void {
    this.params = {
      appStandardModalHeaderLabel: 'Select Teams',
      onSave: () => alert('save me')
    };
  }
}
...