Я создаю свой собственный модальный компонент, пока он идет хорошо, я могу динамически создать сам мой исходный модальный компонент, но затем я пытаюсь создать другой компонент внутри модального компонента.
С моим кодом нижедля компонента модального контейнера у меня есть 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')
};
}
}