typescript 类型“AbstractControl〈any,any>"缺少类型”FormControl“的以下属性< any>

omtl5h9j  于 2023-03-13  发布在  TypeScript
关注(0)|答案(1)|浏览(215)

我有一个显示此自定义组件的父组件

\<app-select-template
                          \[options\]="languagesArray"
                          formControlName="homeLanguage"
                          **\[formControl\]**="correspondencePreferencesForm.controls\['homeLanguage'\]"
                          label="Home Language"
                          headerText="Select Home Language"
                          (selectionChange)="handleSelectionChange($event)"
                          \>
                        \</app-select-template\>

它突出显示TYPE错误:* 类型“AbstractControl〈any,any〉"缺少类型”FormControl“的以下属性:默认值、registerOnChange、registerOnDisabledChangengtsc*

子自定义组件

import { Component, Input, Output, EventEmitter } from '@angular/core';
import { AbstractControl, FormControl} from '@angular/forms';

@Component({
  selector: 'app-select-template',
  template: `
    <div class="w-full">
      <p class="pb-4 text-gems-primary-blue" [textContent]="headerText"></p>
      <mat-form-field appearance="outline">
        <mat-label [textContent]="label"></mat-label>
        <mat-select [formControlName]="formControlName" (selectionChange)="submitFormCtrVal(formControl, $event)">
          <mat-option *ngFor="let option of options" [value]="option.Description | uppercase">
            {{option.Description | uppercase}}
          </mat-option>
        </mat-select>
      </mat-form-field>
    </div>
  `,
  styles: []
})
export class SelectTemplateComponent {
  @Input() options!: any[];
  @Input() label!: string;
  @Input() headerText!: string;
  @Input() formControlName!: string;
  @Input() formControl: FormControl = new FormControl();
  @Output() selectionChange = new EventEmitter();

  submitFormCtrVal(formControl: FormControl, event: any) {
    const selectedValue = event.value;
    const selectionData = {
      formControl: formControl,
      value: selectedValue
    };
    this.selectionChange.emit(selectionData);
  }
  

  
}

请帮帮忙
我试过将控件类型更改为抽象并将其定义为新的窗体控件。没有任何效果。

qoefvg9y

qoefvg9y1#

在嵌套表单时(无论是模板驱动的还是React驱动的表单),你需要一种方法将父表单组“链接”或传播到子组件。否则Angular将不知道formControlName指令链接到哪个表单组。
声明你没有粘贴所有的代码,所以我不得不假设缺失的部分看起来是什么样子,你可以在下面看到,在子组件内部,我获取了(通过依赖注入)父formGroup,并在html模板中重新声明了它,以便mat-select formControlName可以在它上面工作:

父组件:

@Component({
  selector: 'my-app',
  standalone: true,
  imports: [
    CommonModule,
    FormsModule,
    ReactiveFormsModule,
    SelectTemplateComponent,
  ],
  template: `
    <form [formGroup]="correspondencePreferencesForm">
      <app-select-template
        [options]="languagesArray"
        formControlName="homeLanguage"
        ngDefaultControl
        label="Home Language"
        headerText="Select Home Language"
        (selectionChange)="handleSelectionChange($event)"/>
    </form>
  `,
})
export class App {
  readonly languagesArray = [{ Description: 'en' }, { Description: 'fr' }];

  correspondencePreferencesForm = this.formBuilder.group({
    homeLanguage: ['en'],
  });

  constructor(private formBuilder: FormBuilder) {}

  handleSelectionChange(event: any): void {
    const targetFormControl =
      this.correspondencePreferencesForm.controls[event.formControlName];
    console.log('handleSelectionChange()', event.value, targetFormControl);
  }
}

子组件:

@Component({
  selector: 'app-select-template',
  template: `
    <div [formGroup]="formGroup" class="w-full">
      <p class="pb-4 text-gems-primary-blue" [textContent]="headerText"></p>
      <mat-form-field appearance="outline">
        <mat-label [textContent]="label"></mat-label>
        <mat-select [formControlName]="formControlName" (selectionChange)="submitFormCtrVal($event)">
          <mat-option *ngFor="let option of options" [value]="option.Description | uppercase">
            {{option.Description | uppercase}}
          </mat-option>
        </mat-select>
      </mat-form-field>
    </div>
  `,
  standalone: true,
  imports: [
    CommonModule,
    FormsModule,
    ReactiveFormsModule,
    UpperCasePipe,
    MatSelectModule,
  ],
  styles: [],
})
export class SelectTemplateComponent {
  @Input() options!: any[];
  @Input() label!: string;
  @Input() headerText!: string;
  @Input() formControlName!: string;

  @Output() selectionChange = new EventEmitter();

  formGroup: FormGroup;

  constructor(@Optional() private parentFormGroup: FormGroupDirective) {}

  ngOnInit(): void {
    this.formGroup = this.parentFormGroup.form;
  }

  submitFormCtrVal(event: any) {
    const selectedValue = event.value;
    const selectionData = {
      formControlName: this.formControlName,
      value: selectedValue,
    };
    this.selectionChange.emit(selectionData);
  }
}

在子组件内部,以下是重要的部分,因为它们与父组件建立了链接:
constructor(@Optional() private parentFormGroup: FormGroupDirective)
this.formGroup = this.parentFormGroup.form;
<div [formGroup]="formGroup" class="w-full">

**注意1.**正如你所看到的,我还改进了[formControl]属性绑定,它不需要通过@Output()反映目标formControl的变化,你可以简单地依赖formControlName绑定,并作为父组件处理程序的一部分计算出哪一个是目标formControl的变化:

handleSelectionChange(event: any): void {
    const targetFormControl =
      this.correspondencePreferencesForm.controls[event.formControlName];
    console.log('handleSelectionChange()', event.value, targetFormControl);
  }

**注2.**另一件要提到的事情是我的例子是用新的独立组件API制作的,因为这是Stackblitz最新版本生成Playground项目的方式。但是它在使用旧的模块相关方法时也不会有任何问题。

Stackblitz工作示例项目:https://stackblitz.com/edit/angular-cstaxs?file=src%2Fmain.ts

相关问题