简体   繁体   English

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

[英]Ionic 6 - Viewchild null in dynamic component loader

I´m developing an Ionic application that will have a form with controls created dinamically from JSON data.我正在开发一个 Ionic 应用程序,该应用程序将具有一个表单,其中包含从 JSON 数据动态创建的控件。

load-child.directive.ts:加载-child.directive.ts:

import { Directive, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[dynamicChild]'
})
export class DynamicChildLoaderDirective {
  constructor(public viewContainerRef: ViewContainerRef) { }
}

app.module.ts: app.module.ts:

...
@NgModule({
  declarations: [AppComponent, DynamicChildLoaderDirective],
...

home.page.html主页.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:主页.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:动态form.component.html:

<ion-label>{{ control.Name }}</ion-label>  

<ng-template dynamicChild></ng-template>

dynamic-form.component.ts:动态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;
  }
}

The problem is when running the application, the line问题是在运行应用程序时,该行

const componentRef = this.dynamicChild.viewContainerRef.createComponent<DnElement>(this.componente);

returns the following error:返回以下错误:

ERROR Error: Uncaught (in promise): TypeError: this.dynamicChild is undefined

I´m using the following versions:我正在使用以下版本:

Ionic Version: 6.1.5离子版本:6.1.5

Angular Version: 13.3.5角度版本:13.3.5

I´m Using the offical angular docs as guide:我正在使用官方的角度文档作为指南:

https://angular.io/guide/dynamic-component-loader https://angular.io/guide/dynamic-component-loader

I´ve tried to change the static property of the ViewChild to false and move the ngOnInit to the ngAfterViewInit with the same result.我尝试将 ViewChild 的静态属性更改为 false 并将 ngOnInit 移动到 ngAfterViewInit ,结果相同。

Is there anything missing here?这里有什么遗漏吗?

Thanks in advance.提前致谢。

Edit:编辑:

I´ve also tried with viewChildren:我也尝试过 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);
    });

  }

No error presents but it never enters the console.log part of the subscribe.没有错误出现,但它永远不会进入订阅的 console.log 部分。

Finally I managed to get it work.最后我设法让它工作。 The code is ok as is, with the difference that the declaration of the directive has to be done in the page in which I´m using it.代码原样可以,不同之处在于指令的声明必须在我使用它的页面中完成。 In this case in home.module.ts instead of app.module.ts:在这种情况下,在home.module.ts而不是 app.module.ts 中:

...
@NgModule({
  imports: [
    CommonModule,
    FormsModule,ReactiveFormsModule,
    IonicModule,
    HomePageRoutingModule
  ],
  declarations: [HomePage,DynamicFormComponent,DynamicChildLoaderDirective]
})
...

You should call template references when your page fully loaded and for that We have a lifecycle hooks triggered when your page fully loaded:您应该在页面完全加载时调用模板引用,为此我们在页面完全加载时触发了生命周期挂钩:

ngAfterViewInit(){
    this.loadDynamicComponent();
}

try this尝试这个

ngAfterContentInit(){
  this.loadDynamicComponent();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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