151

I'm using ReactiveFormsModule of Angular2 to create a component that contains a form. Here is my code:

foo.component.ts:

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

foo.component.html (with [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 (with 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>

Both ways work. But i cannot figure out what is the difference between using [formControl] and formControlName.

smartmouse
  • 13,912
  • 34
  • 100
  • 166
  • 1
    I'd say that the main reason for using formControlName over formControl is when you don't want to maintain individual FormControl instances in the component. – Paul Samsotha Oct 21 '16 at 08:46

5 Answers5

273

I believe you missed an important point: [formGroup] directive in the second example. formControlName is used together with [formGroup] to save your form multiple dot navigations. For example:

<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>

Is equivalent to:

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

Now imagine nested FormGroups :)

Harry Ninh
  • 16,288
  • 5
  • 60
  • 54
  • 1
    using [formControl]="form.get('Registration.Attributes.aboutme')" caused issues.. but works fine with formControlName="firstNRegistration.Attributes.aboutmeame" – Ricardo Saracino Sep 14 '18 at 13:16
  • 2
    I past two weeks stuck at one activity on my work and your answer save me. Thank you guy! – Lucas Brito Dec 15 '20 at 13:26
  • 1
    I wonder whether formControlName is still a good approach in 2023. With typed forms we now have help from the compiler. If you use [formControl] you get an error if you reference a control that doesn't exist. If you use formControlName this error happens at runtime. Nesting can be achieved by defining an alias like this: `*ngIf="myForm.controls.nested as nested"`. And using form validation you usually have to reference the control in some expression anyways. – fischerman Feb 06 '23 at 09:39
28

[formControl] assigns a reference to the FormControl instance you created to the FormControlDirective.

formControlName assigns a string for the forms module to look up the control by name.

If you create variables for the controls, you also don't need the . as mentioned by Harry, but I'd also suggest to use [formGroup] instead because with more complicated forms this can become messy.

constructor(fb: FormBuilder) {
    this.fullName = new FormControl('', Validators.required);
    this.gender = new FormControl('');
    this.myForm = fb.group({
        'fullname': this.fullName,
        'gender': this.gender
    });
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • when I add this.fullName = new FormControl('', Validators.required); I got an error like you cannot assign because it's read-only property or constant, but here I am taken as a variable.So please help – Brijesh Mavani Feb 05 '18 at 06:21
  • 2
    Please post the **exact** error message. It's probably even better to create a new question containing your code that allows to reproduce – Günter Zöchbauer Feb 05 '18 at 06:23
11

There is a 3rd equivalency to the two provided in the accepted answer, which is this (not recommended):

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

Notice that we are still using the [formGroup] directive.

However, for this template to compile without error, then your component needs to declare the controls as AbstractControls and not FormControls:

myComponent.ts

firstName: AbstractControl
lastName: AbstractControl
email: AbstractControl
title: AbstractControl

However, please note that declaring AbstractControls is not recommended, so if you get the error Cannot find control with unspecified name attribute then it is probable you have mixed the styles or have declared your controls as AbstractControls.

rmcsharry
  • 5,363
  • 6
  • 65
  • 108
  • how can i handle if the input elent is another component. how do I bind the fomrcontrol withe the component – Ramakanth Reddy Sep 25 '19 at 09:10
  • You cannot - even if there IS a way, you should not. The element should be bound to the control defined IN THAT COMPONENT. If you want to pass data to another component then use a service (or if it is parent component then event emitter). Google how to pass data between components – rmcsharry Sep 25 '19 at 12:09
  • can you please look at this post https://stackoverflow.com/questions/58100248/how-do-i-bind-output-values-of-another-component-to-a-form-control-in-my-compone – Ramakanth Reddy Sep 25 '19 at 14:05
4

From the Angular docs (https://angular.io/guide/reactive-forms):

Component

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

Template

<form [formGroup]="profileForm">

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

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

</form>

Note that just as the FormGroup contains a group of controls, the profileForm FormGroup is bound to the form element with the FormGroup directive, creating a communication layer between the model and the form containing the inputs. The formControlName input provided by the FormControlName directive binds each individual input to the form control defined in the FormGroup

Chris Halcrow
  • 28,994
  • 18
  • 176
  • 206
0

with [formControl] you can use Reactive programming advantages because FormControl has a property named valueChanges (I know this one right now, maybe there is more than that) which returns an Observable which you can subscribe and use it. (for example, it is very useful in register scenarios which you want to check input email to be not repeated as soon as user change the value)

Seyed Ali Roshan
  • 1,476
  • 1
  • 18
  • 37
  • Yes. But you still use formControlName in the template, even when using the model in your answer. Just assign the formControlName=“someFormControlName” to a FormControl in the component.ts file like someFormControlName: FormControl; – Charles Robertson Dec 17 '18 at 09:31