I am new to angular 5 so basically am still grasping with the concepts. Using Angular's documentation on reactive forms as an example (https://angular.io/guide/reactive-forms), the following code is as given:
<div formArrayName="secretLairs" class="well well-lg">
<div *ngFor="let address of secretLairs.controls; let i=index" 
 [formGroupName]="i" >
    <!-- The repeated address template -->
  </div>
  </div>
What does secretlairs.controls mean and what is it? According to angular it means that:
The source of the repeated items is the FormArray.controls, not the FormArray itself. Each control is an address FormGroup, exactly what the previous (now repeated) template HTML expected.
Does secretlairs.controls contain any data? Can i replace this portion with lets say an object itself with data of type any and instantiated with data obtained from webapi? For example, instead of
*ngFor="let address of secretLairs.controls
i use
*ngFor="let address of addresses
where addresses is of type any and data obtained from database.
First, there are three type of forms - FormControl, FormGroup, and FormArray - all inherit from AbstractControl.
When you use Reactive Forms for validation and include either formGroupName, formControlName, or formArrayName in the component's template, you are actually declaratively defining a map between the form control tree and the root FormGroup model.
For example, given the following template:
<div [formGroup]="formGroup">
    <div formGroupName="personalInfo">
         First Name: <input type="text" formControlName="firstName"><br />
         Last Name: <input type="text" formControlName="lastName"><br />
    </div>
    <div formArrayName="cities">
        Top cities: <input *ngFor="let city of cities; index as i" type="text" [formControlName]="i">
    </div>
</div>
You are declaratively setting up a form map for collecting information, which will eventually produce a JSON object in a specific format. For example, given the above form model, formGroup.value would return: 
{
   "personalInfo": {
        "firstName: 'John',
        "lastName: 'Smith'
    },
    "cities": [
        "New York",
        "Winnipeg",
        "Toronto"
    ]
 }
Once you've declared the structure of your form group in your template, you need to imperatively create the corresponding formGroup, formControl, and formArray in your component class.   As you setup each form, you have the opportunity to set up additional parameters: 
  1. Initial Form Value
  2. Array of synchronous validators
  3. Array of asynchronous validators
This applies to any of the abstract controls.
This is what the corresponding formGroup model would look like given the above template:
export class AppComponent {
  firstName: string,
  lastName: string;
  cities: string[];
  @Input() formGroup: FormGroup;
  constructor(private fb: FormBuilder) {
    // setup initial values
    this.cities = ['New York', 'Winnipeg', 'Toronto'];
    this.firstName = 'John';
    this.lastName  = 'Smith';
    // create a formGroup that corresponds to the template
    this.formGroup = fb.group({
      firstName: [this.firstName, Validators.required],
      lastName: [this.lastName, Validators.required],
      cities: fb.array(this.cities.map(t=> fb.control(t, Validators.required)))
    })
  }
}
To bind to any of the form's validation flags, you can use the root formGroup and a path string (which supports dots) to find the particular group, control, or array.
For example:
<div *ngIf="formGroup.get('firstName').errors.required">First Name is Required</div>
Hopefully, that makes it clear.
[Edit]
Better yet, given that Reactive Forms is all about declaratively setting up a model in the template, and mapping the same model imperatively in the component class, you should consider defining a JSON model and using that instead.
For example, suppose we have a custom model MyModel which has a firstName property, lastName property, and a cities property.  The component class would look like this: 
 export class AppComponent {
  @Input() model: MyModel;
  @Output() modelChange: EventEmitter<MyModel>;
  @Input() formGroup: FormGroup;
  constructor(private fb: FormBuilder) {
    this.model = new EventEmitter<MyModel>();
    // create a formGroup that corresponds to the template
    this.formGroup = fb.group({
      firstName: [this.model.firstName, Validators.required],
      lastName: [this.model.lastName, Validators.required],
      cities: fb.array(this.model.cities.map(t=> fb.control(t, Validators.required)))
    });
  }
  onSubmit() {
     if (this.formGroup.valid) {
        this.model = this.formGroup.value;
        this.modelChange.next(this.model);
     }
  }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With