繁体   English   中英

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

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM