Skip to content

Conversation

kara
Copy link
Contributor

@kara kara commented Jul 27, 2016

This PR adds some clearer error messages for invalid form states.

Case 1: Mixing formControlName with template driven form strategy

<form>
   <div ngModelGroup="person">
      <input formControlName="name">
   </div>
</form>

Before

Error: Cannot setParent of null

After

Error: formControlName cannot be used with an ngModelGroup parent. It is only compatible
with parents that also have a "form" prefix: formGroupName, formArrayName, or formGroup.

Option 1:  Update the parent to be formGroupName (reactive form strategy)

<div [formGroup]="myGroup">
   <div formGroupName="person">
      <input formControlName="firstName">
   </div>
</div>

In your class:

this.myGroup = new FormGroup({
   Person: new FormGroup({ firstName: new FormControl() }) 
});

Option 2: Use ngModel instead of formControlName (template-driven strategy)

<form>
   <div ngModelGroup="person">
      <input [(ngModel)]="person.name" name="firstName">
   </div>
</form>

Case 2: Trying to use ngModel to register a form control with formGroup

<div [formGroup]="myGroup">
   <input [(ngModel)]="person.name" name="firstName">
</div>

Before
No error! But the form control will not behave predictably because the ngModel's control instance conflicts with the user's control instance.

After

Error: ngModel cannot be used to register form controls with a parent formGroup directive.
Try using formGroup's partner directive "formControlName" instead.

Example:

<div [formGroup]="myGroup">
   <input formControlName="firstName">
</div>

In your class:
this.myGroup = new FormGroup({
   firstName: new FormControl()
});

Or, if you'd like to avoid registering this form control, indicate that it's
standalone in ngModelOptions:

Example:

<div [formGroup]="myGroup">
   <input [(ngModel)]="showMoreControls" [ngModelOptions]="{standalone: true}">
</div>

@kara kara added the action: review The PR is still awaiting reviews from at least one requested reviewer label Jul 27, 2016
@kara kara force-pushed the error branch 4 times, most recently from e9f5dd3 to 99e1d0d Compare July 27, 2016 06:04
@vsavkin vsavkin added pr_state: LGTM and removed action: review The PR is still awaiting reviews from at least one requested reviewer labels Jul 27, 2016
@kara kara merged commit 43349dd into angular:master Jul 27, 2016
@unsafecode
Copy link

unsafecode commented Aug 24, 2016

@kara I came over this PR after a whole day spent investigating what broke our RC3 app after the upgrade to RC5. We were using ngModel to bind the data and FormGroup+FormControl to apply complex validation logic, like:

<div [formGroup]="myGroup">
   <input formControlName="firstName" [(ngModel)]="firstName">
</div>

So far, in RC5, this approach no longer works. On one hand, we need to retain the validation logic, on the other we would really need to avoid rebuild the components' logic to get/set data through FormControls.

What can we do to migrate effectively?

@kara
Copy link
Contributor Author

kara commented Aug 24, 2016

@unsafecode The code snippet you posted is still supported and should actually work fine. What error are you getting? Can you post a sample plunker?

@unsafecode
Copy link

@kara I'm getting the exact one at the top.

Error: ngModel cannot be used to register form controls with a parent formGroup directive.
Try using formGroup's partner directive "formControlName" instead.

Trying to setup a plunker in the meanwhile

@kara
Copy link
Contributor Author

kara commented Aug 24, 2016

@unsafecode The thing that doesn't make sense about that is it's an ngModel error: https://github.com/angular/angular/blob/master/modules/%40angular/forms/src/directives/template_driven_errors.ts. In the snippet you pasted, ngModel is not activated. Its selector excludes elements that have formControlName. Only formControlName should be activated. Are you sure that's the code that's causing the error?

@unsafecode
Copy link

unsafecode commented Aug 24, 2016

@kara Now I got it: there were some elements with the name attribute, instead of formControlName. So, this sample does NOT work and throws the aforementioned error:

<div [formGroup]="myGroup">
   <input name="firstName" [(ngModel)]="firstName">
</div>

While the following, with the formControlName works just fine:

<div [formGroup]="myGroup">
   <input formControlName="firstName" [(ngModel)]="firstName">
</div>

@kara
Copy link
Contributor Author

kara commented Aug 24, 2016

Yep, the top code sample is deliberately not supported. formGroup expects you to create your own FormControl instances, whereas ngModel creates FormControl instances implicitly for you. You can't have two conflicting FormControl instances on the same form control element. When you use formControlName, ngModel does not activate or create a control (it's simply used as an @input). formControlName just links to the existing input you created in your class.

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 9, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants