[英]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.