Ionic 6 -动态组件加载器中的Viewchild为空



我正在开发一个Ionic应用程序,它将有一个从JSON数据动态创建的带有控件的表单。

load-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],
...

home.page.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>
...

home.page.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;
});
}
}

dynamic-form.component.html:

<ion-label>{{ control.Name }}</ion-label>  
<ng-template dynamicChild></ng-template>

dynamic-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

我正在使用以下版本:

Ionic Version: 6.1.5

Angular版本:13.3.5

我使用angular官方文档作为指南:

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();
}

try this

ngAfterContentInit(){
this.loadDynamicComponent();
}

最新更新