如何使用 formControlName 和处理嵌套的 formGroup?

How to use formControlName and deal with nested formGroup?

正如 Angular documentation 所说,我们可以在表单中使用 formControlName

<h2>Hero Detail</h2>
<h3><i>FormControl in a FormGroup</i></h3>
<form [formGroup]="heroForm" novalidate>
    <div class="form-group">
        <label class="center-block">Name:
            <input class="form-control" formControlName="name">
        </label>
    </div>
</form>

正如他们所说...

Without a parent FormGroup, [formControl]="name" worked earlier because that directive can stand alone, that is, it works without being in a FormGroup. With a parent FormGroup, the name input needs the syntax formControlName=name in order to be associated with the correct FormControl in the class. This syntax tells Angular to look for the parent FormGroup, in this case heroForm, and then inside that group to look for a FormControl called name.

无论如何,几个月前我问 弄清楚 formControlName[formControl] 之间有什么区别。

现在我的问题是:将 formControlName 与嵌套的 FormGroup 一起使用怎么样?

例如,如果我有以下表单结构:

this.myForm = fb.group({
    'fullname': ['', Validators.required],
    'gender': [],
    'address': fb.group({
        'street': [''],
        'houseNumber': [''],
        'postalCode': ['']
    })
});

使用formControlName将"street"(或"houseNumber"或"postalCode")绑定到相关HTML元素的正确方法是什么?

您可以使用 Form 组,它基本上是控件的集合(控件是指您的 html 表单中给出的字段)在您的打字稿语法中定义并使用 formControlName 绑定到您的 HTML 元素指令,例如

this.myForm = fb.group({
    'fullname': ['', Validators.required],
    'gender': [],
    'address': fb.group({
        'street': [''],
        'houseNumber': [''],
        'postalCode': ['']
    })
});

模板:

<form [formGroup]="myForm" >
   <div class="form-group">
      <label for="fullname">Username</label>
      <input type="text" id="username" formControlName="fullname" class="form-control">            
   </div>
   <div class="radio" *ngFor="let gender of genders">
      <label>
      <input type="radio" formControlName="gender" [value]="gender">{{ gender }} </label>
   </div>
   <div formGroupName="address">
      <div class="form-group">
         <label for="street">Username</label>
         <input type="text" id="username" value="street" formControlName="street" class="form-control">            
      </div>
      <div class="form-group">
         <label for="houseNumber">Username</label>
         <input type="text" id="username" value="street" formControlName="houseNumber" class="form-control">            
      </div>
      <div class="form-group">
         <label for="postalCode">Username</label>
         <input type="text" id="username" value="street" formControlName="postalCode" class="form-control">            
      </div>
   </div>
</form>

一个 formGroup 可以由一个嵌套的 formGroup 组成,层次结构可以继续,但是在访问值时它相当简单。

这是真的。查看 formGroupName

this.myForm = fb.group({
    'fullname': ['', Validators.required],
    'gender': [],
    'address': fb.group({
        'street': [''],
        'houseNumber': [''],
        'postalCode': ['']
    })
});

<form [formGroup]="myForm" >
   <div class="form-group">
      <label for="fullname">Username</label>
      <input type="text" id="username" formControlName="fullname" class="form-control">            
   </div>
   <div class="radio" *ngFor="let gender of genders">
      <label>
      <input type="radio" formControlName="gender" [value]="gender">{{ gender }} </label>
   </div>
   <div formGroupName="address">
      <div class="form-group">
         <label for="street">Username</label>
         <input type="text" id="username" value="street" formControlName="street" class="form-control">            
      </div>
      <div class="form-group">
         <label for="houseNumber">Username</label>
         <input type="text" id="username" value="street" formControlName="houseNumber" class="form-control">            
      </div>
      <div class="form-group">
         <label for="postalCode">Username</label>
         <input type="text" id="username" value="street" formControlName="postalCode" class="form-control">            
      </div>
   </div>
</form>

tl;博士:

您可以将表单分解为使用嵌套 formgroups 的组件,并且 formcontrolname 可以正常使用。

由于嵌套的表单组通常用于指定表单的单独部分,我倾向于使用的方法是将其分解为组件并将这些组件作为输入参数传递给嵌套的表单组。 因此,在您的情况下,我会有一个 address 组件,该组件将表单组作为参数:

<app-address [formGroup]="myForm.get('address')"></app-address

在该组件内部,我将有一个 @Input() formGroup 将用于 html:

<div [formGroup]="formGroup">
....

这样您就可以像往常一样显式引用控件名称,因为它将成为此表单组的一部分。

另外,请记住表格是作为参考传递的。您的更改将在父组件的 myForm 元素中说明,如果您需要访问不在您的表单组中的表单部分(验证、更改检测等),您总是可以传递整个表单并将表单组定义为明确引用内部组:

<div [formGroup]="formGroup.get('adress')">

(假设您传递了整个表单对象

编码愉快!

I am struggling with a problem in Angular 10. I have a "parent" form group "forma" who has a few dependent groups: "company", and at the same time, "company" has two "children" with another groups, msgAccounts and socialMedia. When I fill the form and I submit it, in the backend everything is correct, I can see how these data is stored in the db correctly, but when I receive this json I cannot display the data inside "company.msgAccounts" and "company.socialMedia" in the controls (inputs). This is what I get from the server:

            {
            name:'',
            active: '',
            ........
            company:{
              msgAccounts:{line: "@linedemo", whatsapp: "0325554244"},
              socialMedia: {fb: '', tw: '', is: ''}
             }   
            ..........
            }
    
 this.forma = this.fb.group( {
          siteName  : [ '', [Validators.required, Validators.minLength(5)]],
          siteEmail  : [ '', [Validators.required, Validators.minLength(5)]],
          // defaultLocation: [ '', [Validators.required, Validators.minLength(10)]],
          active  : [ true, [Validators.required, Validators.minLength(5)]],
          mainLanguage: ['' , [Validators.required, Validators.minLength(2)]],
        
          company: this.fb.group({
            name: [''],
            address: [''],
            phone: [''],
            msgAccounts: this.fb.group({
              line: [],
              whatsapp: []
            }),
            socialMedia: this.fb.group({
              fb: [],
              is: [],
              tw: []
            })
          })
        });
    
    And the html: (Sorry about the indentation, when it was not easy using this editor, and I just pasted a part of the code in order to do it as shorter as possible).
    
            <mat-tab-group>   
                    <mat-tab label="settings">
                        <form autocomplete="off" >
                            <ng-template ng-template matTabContent> 
                                <mat-tab-group  [formGroup]="forma">
                                        <mat-tab label="global"> 
                                           // All this fields have are fine
                                         </mat-tab>
    
                                 <mat-tab formGroupName="company" label="company"> 
                                    <div class="card">
                                        <div class="card-header" id="headingTwo">
                                            <h5 class="mb-0">Details</h5>
                                        </div>
                                        <div id="company-details">
                                                <div class="form-group row">
                                                    <div class="col-sm-3">
                                                        <input 
                                                        type="text" 
                                                        class="form-control" 
                                                        id="name" 
                                                        name="name"
                                                        placeholder="Company name"
                                                        formControlName=name>
                                                    </div>
                        
                                                </div>
    
                             <div class="form-group row" formGroupName="msgAccounts">
                                                    <div class="col-sm-6">
                                             
                                                        <input 
                                                        type="text" 
                                                        class="form-control" 
                                                        id="line" 
                                                        name="line"
                                                        placeholder="line"
                                                        formControlName=line>
                                                    </div>
                                                    <div class="col-sm-6">
                                                    
                                                        <input 
                                                        type="text" 
                                                        class="form-control" 
                                                        id="whatsapp" 
                                                        name="whatsapp"
                                                        placeholder="whatsapp"
                                                        formControlName=whatsapp>
                                                    </div>
                                                </div>
    
                                                    
    
                             <div class="form-group row" formGroupName="socialMedia" >
                         
                                                    <div class="col-sm-6">
                                                        <input 
                                                        type="text" 
                                                        class="form-control" 
                                                        id="is" 
                                                        name="is"
                                                        placeholder="Is"
                                                        formControlName=is>
                                                    </div>
                                                </div>                             
                                            </div>
                                       </div>
                                </mat-tab>                 
               </mat-tab-group>  
                            <div class="form-group row">
                            <div class="col-sm-10">
                               <button type="submit" 
                                   (click)="saveConfig()">Save</button>
                            </div>
            </div>
                        
           </ng-template>
          </form>
       </mat-tab>
    </mat-tab-group>