到目前为止,我正在创建自己的模态组件,它可以动态创建我的初始模态组件,但后来我尝试在模态组件中创建另一个组件。
使用下面的代码,对于模态容器组件,我在模板变量上有一个viewCotainerRef,然后在该容器div中创建组件。当我尝试在DynamicContentComponent
内部渲染我的ModalComponent
时,我的问题就到了,我在第一次点击时无法获得viewContainerRef,因为它是undefined
,但是在第二次单击模态触发器时它是定义。
所以当我生成DynamicContentComponent
时,我会在ModalComponent
上设置'viewContainerRef'。将它发送到渲染服务,当我可以清楚地看到它控制台登出时很好。但是当我使用相同的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上,它是为内容组件设置第二个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')
};
}
}