模板错误类型“AbstractControl”无法分配给类型“FormControl”

问题描述 投票:0回答:11

为什么我会收到此错误?

以下代码适用于另一个应用程序

          <input class="form-control form-control-sm" type="number" min="0"
            [formControl]='invoiceForm.get("quantity")'>

在这个新应用程序中它也可以工作,但仍然在终端中抱怨

  Type 'AbstractControl' is not assignable to type 'FormControl'.
angular angular-reactive-forms
11个回答
41
投票
<input type="password" placeholder="Confirm Password" class="form-control" [formControl]="$any(myForm).controls['confirmpassword']"/> 

使用 $any 函数禁用类型检查。我用这个解决了我的错误。


34
投票

如果其他人仍然遇到这个问题,我分享我的解决方案,它与Bellash描述的几乎相同,但性能更好。 对于这个例子:

<input class="form-control form-control-sm" type="number" min="0"
        [formControl]='invoiceForm.get("quantity")' | formControl>

我们只需要创建并使用管道,它将返回正确类型的值

@Pipe({
    name: 'formControl',
})
export class FormControlPipe implements PipeTransform {
    transform(value: AbstractControl): FormControl<typeof value['value']> {
        return value as FormControl<typeof value['value']>;
    }
}

通过这种方式,您将获得更好的性能,因为仅当提供的表单发生更改时才会调用管道转换函数。

通常在模板中使用函数是不好的做法,因为每个生命周期更改都会调用此函数,并且在较大的项目上会产生很大的性能问题。最好的方法是使用管道(通常正是为了此类目的而开发的),仅在渲染时转换某些值(仅当某些值需要更改时)。 希望这会对某人有所帮助)


13
投票

如果您使用 Angular 9 或更高版本,此问题可能来自

tsconfig.json

"angularCompilerOptions": {
    ...
    "strictTemplates": true <-- causing "Type 'AbstractControl' is not assignable to type 'FormControl'"
  }

第一个选项

通过设置

"strictTemplates": false
可能会暂时“解决”问题

第二个选项

通过模板将

AbstractControl
转换为
FormControl
,所以你的
.ts
文件应该有

convertToFormControl(absCtrl: AbstractControl | null): FormControl {
    const ctrl = absCtrl as FormControl;
    return ctrl;
  }

还有你的

html

<input
    type="text"
    [formControl]="convertToFormControl(invoiceForm.get("quantity"))"
  />

9
投票

从这个官方文档以及根据FormControl定义,我们可以看到FormControl继承自AbstractControl。由于

FormGroup.controls
FormGroup.get("key")
都返回
AbstractControl
,我必须创建一个函数来从 Parent 类转换为 Child 类。

toControl(absCtrl: AbstractControl): FormControl {
    const ctrl = absCtrl as FormControl;
    // if(!ctrl) throw;
    return ctrl;
}

和模板

 <input class="form-control form-control-sm" type="number" min="0"
        [formControl]='toControl(invoiceForm.get("quantity"))'>

PS:我无法使用

FormControlName
,因为我有很多表单组和子组/数组。那就是我必须使用banana in box指令,因为它的值是强类型的

编辑 2022:另请考虑下面的 @Avetik 答案,将此函数转换为管道以获得更好的性能


4
投票

感谢 Avetik 和 Imo 提供我列出的大部分信息。以下步骤适用于 Angular 13+:

在基础项目文件夹中创建文件 form-control.pipe.ts:

import {Pipe, PipeTransform} from '@angular/core';
import {AbstractControl, FormControl} from '@angular/forms';

@Pipe({
    name: 'formControl',
})
export class FormControlPipe implements PipeTransform {
    transform(value: AbstractControl): FormControl {
        return value as FormControl;
    }
}

在项目的 @NgModule 的声明部分中,将 FormControlPipe 添加到列表中并导入它。

在任何地方收到此 lint 警告,请添加 | FormControl(包括管道符号)

[formControl]="form.get('wordRuleForm').get('sound') | formControl"

问题解决了!

我有一个与formGroup类似的控件,所以我基于formGroup创建了一个类似的过滤器,它的使用方式如下:

[commonForm]="form.get('commonForm') | formGroup"

2
投票

我可以通过让模板直接访问

FormControl
并将其添加到
initForm()
中的表单来解决这个问题。

.ts

form: FormGroup = new FormGroup({});
quantity: FormControl = new FormControl(Quantity.MIN, [
  Validators.min(Quantity.MIN),
  Validators.max(Quantity.MAX),
]);

ngOnInit(): void {
  this.initForm();
}

initForm(): void {
  this.form.addControl('quantity', this.quantity);
}

.html(在我的例子中,我将

FormControl
数量传递给一个自定义组件,该组件采用名为“control”的
FormControl
Input()
。)

<form [formGroup]="form" (ngSubmit)="submit()">
  <app-select-quantity [control]="quantity"></app-select-quantity>
  <div>
    <button
      mat-flat-button
      type="submit"
      color="primary"
      [disabled]="!form.valid"
    >
      Submit
    </button>
  </div>
</form>

2
投票
<input type="name" placeholder="Name" class="form-control" [formControl]="$any(cardForm).controls.name" />

这里

$any
函数将禁用类型检查。


1
投票

我并不是很热衷于使用解决方法(所有答案似乎都是如此),并且碰巧遇到了 Angular University 示例中使用的策略。

您可以通过将

get
属性公开给模板上的
formControlName
来轻松地将表单控件公开给表单:

<input class="form-control form-control-sm" type="number" min="0"
formControlName='quantity'> <!-- formControlName instead of [formControl] -->

在组件中:

// The get property should match the formControlName above.
get quantity() {
  return this.form.controls["quantity"];
}

0
投票

这个 Angular 问题与切线相关,但很有趣 - 对于自定义类型的表单:

(表单):类型化表单和泛型/继承的问题。 https://github.com/angular/angular/issues/47091


-1
投票

你可以试试

<input class="form-control form-control-sm" type="number" min="0"
            [formControl]='invoiceForm.controls.quantity'>

或者我个人最喜欢的处理表单的方式

<div [formGroup]="inviceForm"> <!-- any tag that wraps all of your controls -->

      <!-- some input before (anything)-->
      <input class="form-control form-control-sm" type="number" min="0"
                formControlName='quantity'>
           <!-- some inputs after (anything)-->
</div>

-1
投票

如果存在不同版本或没有“类型”转换匹配,您可以使用“任何”作为临时解决方案。例如

来自:

event: FormControl

致:

event: any
© www.soinside.com 2019 - 2024. All rights reserved.