[英]Ionic 6 - Viewchild null in dynamic component loader
我正在开发一个 Ionic 应用程序,该应用程序将具有一个表单,其中包含从 JSON 数据动态创建的控件。
加载-child.directive.ts:
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[dynamicChild]'
})
export class DynamicChildLoaderDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}
app.module.ts:
...
@NgModule({
declarations: [AppComponent, DynamicChildLoaderDirective],
...
主页.html
...
<ion-content [fullscreen]="true" class="ion-padding">
<form [formGroup]="testForm">
<ion-card *ngFor="let objGrupo of grupos">
<ion-card-header>
<ion-card-title>{{objGrupo.label}}</ion-card-title>
</ion-card-header>
<ion-card-content *ngFor="let objControl of objGrupo.controls">
<app-dynamic-form [control]="objControl" [form]="testForm"></app-dynamic-form>
</ion-card-content>
</ion-card>
</form>
</ion-content>
...
主页.ts:
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { DynamicFormGroup } from '../models/dynamic_form_group';
import { Ticket } from '../models/ticket';
import { TicketService } from '../services/ticket.service';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
grupos: DynamicFormGroup[] = [];
testControl: any = {};
testForm: FormGroup;
validation_messages: any;
constructor(public formBuilder: FormBuilder,private ticketService: TicketService) {
this.ticketService.obtenerFormularioTicket()
.subscribe(obtainedInfo => {
var ticket: Ticket = obtainedInfo;
this.grupos = ticket.getFormList();
this.testControl = this.grupos[0].controls;
});
}
}
动态form.component.html:
<ion-label>{{ control.Name }}</ion-label>
<ng-template dynamicChild></ng-template>
动态form.component.ts:
import { Component, Input, OnInit, Type, ViewChild } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { DynamicChildLoaderDirective } from 'src/app/directives/load-child.directive';
import { DnElement } from '../dn-element/dn-element.component';
import { DnInputTextComponent } from '../dn-input-text/dn-input-text.component';
import { DnLabelComponent } from '../dn-label/dn-label.component';
@Component({
selector: 'app-dynamic-form',
templateUrl: './dynamic-form.component.html',
styleUrls: ['./dynamic-form.component.scss'],
})
export class DynamicFormComponent implements OnInit {
@ViewChild(DynamicChildLoaderDirective, { static: true }) dynamicChild!: DynamicChildLoaderDirective;
@Input() control: any;
@Input() form: FormGroup;
componente: Type<any>;
ngOnInit(): void {
this.loadDynamicComponent();
}
private loadDynamicComponent() {
if(!this.control.Editable){
this.componente = DnLabelComponent;
}else{
this.componente = DnInputTextComponent;
}
const componentRef = this.dynamicChild.viewContainerRef.createComponent<DnElement>(this.componente);
componentRef.instance.objControl = this.control;
componentRef.instance.form = this.form;
}
}
问题是在运行应用程序时,该行
const componentRef = this.dynamicChild.viewContainerRef.createComponent<DnElement>(this.componente);
返回以下错误:
ERROR Error: Uncaught (in promise): TypeError: this.dynamicChild is undefined
我正在使用以下版本:
离子版本:6.1.5
角度版本:13.3.5
我正在使用官方的角度文档作为指南:
https://angular.io/guide/dynamic-component-loader
我尝试将 ViewChild 的静态属性更改为 false 并将 ngOnInit 移动到 ngAfterViewInit ,结果相同。
这里有什么遗漏吗?
提前致谢。
编辑:
我也尝试过 viewChildren:
export class DynamicFormComponent implements OnInit {
@ViewChild(DynamicChildLoaderDirective, { static: true }) dynamicChild!: DynamicChildLoaderDirective;
@ViewChildren(DynamicChildLoaderDirective) viewChildren!: QueryList<DynamicChildLoaderDirective>;
@Input() control: any;
@Input() form: FormGroup;
componente: Type<any>;
ngOnInit(): void {
//this.loadDynamicComponent();
}
ngAfterViewInit() {
// viewChildren is set
this.viewChildren.changes.subscribe((r) => {
console.log(this.viewChildren);
});
}
没有错误出现,但它永远不会进入订阅的 console.log 部分。
最后我设法让它工作。 代码原样可以,不同之处在于指令的声明必须在我使用它的页面中完成。 在这种情况下,在home.module.ts而不是 app.module.ts 中:
...
@NgModule({
imports: [
CommonModule,
FormsModule,ReactiveFormsModule,
IonicModule,
HomePageRoutingModule
],
declarations: [HomePage,DynamicFormComponent,DynamicChildLoaderDirective]
})
...
您应该在页面完全加载时调用模板引用,为此我们在页面完全加载时触发了生命周期挂钩:
ngAfterViewInit(){
this.loadDynamicComponent();
}
尝试这个
ngAfterContentInit(){
this.loadDynamicComponent();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.