formControlName和FormControl有什么区别?

155

我正在使用 Angular2 的 ReactiveFormsModule 来创建一个包含表单的组件。以下是我的代码:

foo.component.ts:

constructor(fb: FormBuilder) {
    this.myForm = fb.group({
        'fullname': ['', Validators.required],
        'gender': []
    });
}

foo.component.html(带有[formControl]):

<div class="fields">
    <div class="field">
        <label>Fullname*</label>
        <input type="text" [formControl]="myForm.controls.fullname"/>
    </div>
</div>

<div class="inline fields">
    <label for="gender">Gender</label>
    <div class="field">
        <div class="ui radio checkbox">
            <input type="radio" name="gender" checked="" tabindex="0" class="hidden" [formControl]="myForm.controls.gender">
            <label>Male</label>
        </div>
    </div>
    <div class="field">
        <div class="ui radio checkbox">
            <input type="radio" name="gender" tabindex="0" class="hidden" [formControl]="myForm.controls.gender">
            <label>Female</label>
        </div>
    </div>
</div>

foo.component.html(使用 formControlName):

<div class="fields">
    <div class="field">
        <label>Fullname*</label>
        <input type="text" formControlName="fullname"/>
    </div>
</div>

<div class="inline fields">
    <label for="gender">Gender</label>
    <div class="field">
        <div class="ui radio checkbox">
            <input type="radio" name="gender" checked="" tabindex="0" class="hidden" formControlName="gender">
            <label>Male</label>
        </div>
    </div>
    <div class="field">
        <div class="ui radio checkbox">
            <input type="radio" name="gender" tabindex="0" class="hidden" formControlName="gender">
            <label>Female</label>
        </div>
    </div>
</div>

两种方式都可以使用,但我无法弄清楚使用 [formControl]formControlName 之间的区别。


1
我认为使用formControlName而不是formControl的主要原因是当您不想在组件中维护单个FormControl实例时。 - Paul Samsotha
5个回答

277

我相信你错过了一个重要的点:[formGroup]指令在第二个例子中。 formControlName[formGroup]一起使用,以保存多点导航的表单。例如:

<div>
  <input type="text" [formControl]="myForm.controls.firstName"/>
  <input type="text" [formControl]="myForm.controls.lastName"/>
  <input type="text" [formControl]="myForm.controls.email"/>
  <input type="text" [formControl]="myForm.controls.title"/>
</div>

等价于:

<div [formGroup]="myForm">
  <input type="text" formControlName="firstName"/>
  <input type="text" formControlName="lastName"/>
  <input type="text" formControlName="email"/>
  <input type="text" formControlName="title"/>
</div>

现在想象一下嵌套的FormGroups :)


1
使用[formControl]="form.get('Registration.Attributes.aboutme')"会导致问题...但使用formControlName="firstNRegistration.Attributes.aboutmeame"可以正常工作。 - Ricardo Saracino
2
我在工作中卡了两个星期,困扰着一个活动,你的回答救了我。谢谢你! - Lucas Brito
1
我想知道在2023年是否仍然使用FormControlName是一个好的方法。通过类型化表单,我们现在可以从编译器获得帮助。如果您使用[formControl],当您引用不存在的控件时,会出现错误。如果您使用FormControlName,则此错误会在运行时发生。可以通过像这样定义别名来实现嵌套:*ngIf="myForm.controls.nested as nested"。并且在使用表单验证时,通常必须在某些表达式中引用该控件。 - fischerman

29

[formControl] 将对创建的 FormControl 实例的引用分配给 FormControlDirective

formControlName 分配一个字符串,以便表单模块按名称查找控件。

如果您为控件创建变量,则不需要像 Harry 提到的那样使用 .,但我建议使用 [formGroup],因为对于更复杂的表单,这可能会变得混乱。

constructor(fb: FormBuilder) {
    this.fullName = new FormControl('', Validators.required);
    this.gender = new FormControl('');
    this.myForm = fb.group({
        'fullname': this.fullName,
        'gender': this.gender
    });
}

当我添加这个.fullName = new FormControl('', Validators.required);时,我收到了一个错误,说你不能分配它,因为它是只读属性或常量,但在这里我将其作为变量。所以请帮忙。 - Brijesh Mavani
2
请发布“确切”的错误信息。最好的方法可能是创建一个新问题,其中包含您的代码,以便能够重现。 - Günter Zöchbauer

11

在已接受答案提供的两种方法之外,还有第三种等效方法(不建议使用):

<div [formGroup]="myForm">
  <input type="text" [formControl]="firstName"/>
  <input type="text" [formControl]="lastName"/>
  <input type="text" [formControl]="email"/>
  <input type="text" [formControl]="title"/>
</div>

请注意,我们仍然使用 [formGroup] 指令。
但是,为了使此模板能够编译而不出错,您的组件需要将控件声明为 AbstractControls 而不是 FormControls:
myComponent.ts
firstName: AbstractControl
lastName: AbstractControl
email: AbstractControl
title: AbstractControl

然而,请注意声明AbstractControls是不被推荐的,所以如果你遇到错误Cannot find control with unspecified name attribute,则很可能是因为你混淆了样式或者将控件声明为AbstractControls。


如何处理输入元素是另一个组件的情况?如何将FormControl与组件绑定? - Ramakanth Reddy
即使有办法,你也不应该这样做。元素应该绑定到在该组件中定义的控件上。如果要将数据传递到另一个组件,则应使用服务(或如果它是父组件,则使用事件发射器)。Google如何在组件之间传递数据。 - rmcsharry
请您查看这篇帖子:https://stackoverflow.com/questions/58100248/how-do-i-bind-output-values-of-another-component-to-a-form-control-in-my-compone - Ramakanth Reddy

4

以下是从Angular文档中翻译的内容(来源:https://angular.io/guide/reactive-forms):

组件

@Component({
  ...
})
export class ProfileEditorComponent {
  profileForm = new FormGroup({
    firstName: new FormControl(''),
    lastName: new FormControl(''),
  });
}

模板

<form [formGroup]="profileForm">

  <label>
    First Name:
    <input type="text" formControlName="firstName">
  </label>

  <label>
    Last Name:
    <input type="text" formControlName="lastName">
  </label>

</form>

请注意,就像 FormGroup 包含一组控件一样,profileForm FormGroup 与使用 FormGroup 指令绑定的表单元素相关联,创建了模型和包含输入的表单之间的通信层。由 FormControlName 指令提供的 formControlName 输入将每个单独的输入与在 FormGroup 中定义的表单控件绑定。

0

使用[formControl],您可以利用响应式编程的优势,因为FormControl有一个名为valueChanges的属性(我现在知道这个,也许还有更多),它返回一个Observable,您可以订阅并使用它。(例如,在注册场景中非常有用,您希望检查输入电子邮件是否在用户更改值后立即重复)


是的。但即使在使用您的答案中的模型时,您仍然需要在模板中使用formControlName。只需在component.ts文件中将formControlName =“someFormControlName”分配给一个FormControl,例如:someFormControlName:FormControl; - Charles Robertson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接