Search code examples
angularangular13

How to bind FormGroup properties to my child component in Angular 13?


I have been solving this problem for 3 days now and can't seem to find a solution. I also tried to use ChatGPT and reading Angular documentation but no luck.

Here is a stackblits link: https://stackblitz.com/edit/angular-ivy-rdwj1n?file=src/app/users-profile/users-profile.component.html

basically, I have a FormGroup in my parent component that I initialized with default values outside my constructor:

  formUsersInformation: FormGroup = this.formBuilder.group({

    profile: this.formBuilder.group({
      firstname: new FormControl('', [Validators.required, Validators.minLength(2)]),
      middlename: new FormControl('', [Validators.required, Validators.minLength(2)]),
      lastname: new FormControl('', [Validators.required, Validators.minLength(2)]),
      birthdate: new FormControl('', [Validators.required]),
      civilstatus: new FormControl('', [Validators.required, Validators.minLength(2)]),
      emailaddress: new FormControl('', [Validators.required, Validators.email]),
      phonenumber: new FormControl('', [Validators.required, Validators.pattern('^[0-9]+$')])
    }),


    addresses: this.formBuilder.array([
      this.formBuilder.group({
        idtype: new FormControl('', [Validators.required]),
        idnumber: new FormControl('', [Validators.required]),
        idexpiration: new FormControl('', [Validators.required]),
        idfile: new FormControl('', [Validators.required]),
      })
    ]),



    identifications: this.formBuilder.array([
      this.formBuilder.group({
        street: new FormControl('', [Validators.required]),
        city: new FormControl('', [Validators.required]),
        state: new FormControl('', [Validators.required]),
        zipcode: new FormControl('', [Validators.required])
      })
    ]),

  });

then in my parent HTML I have this:

<app-users-profile 
      [formUsersProfile]="formUsersInformation" 
      (FormActionEvent)="formsAction($event)" 
      *ngIf="isUsersProfileVisible">
</app-users-profile>

In my Child Component I named it UsersProfileComponent I have an @Input() decorator outside my constructor:

@Input() formUsersProfile: FormGroup = new FormGroup({});

And what I want to do is to bind formUsersInformation profile property in my HTML. This is my html form:

<div class="row" [formGroup]="formUsersProfile">

        <div class="col-md-4 mb-4">
            <label for="firstname" class="form-label">First Name</label>
            <input type="text" class="form-control radius-none"  formControlName="firstname"  id="firstname">
        </div>
</div>

but it says: ERROR Error: Cannot find control with name: 'firstname'

Also I also need to bind the other properties to my other child component such as addresses (which is an array) for UsersAddressComponent and identifications for my UsersIdentificationComponent which is also an array.

Thank you very much!


Solution

  • Here is a solution to your question.
    https://stackblitz.com/edit/angular-ivy-gv4pnw?file=src/app/app.component.html

    What you need is to use the right combination of formGroupName, formControlName and formArrayName directives. Here is the markup of resulting child component:

    <div class="row" [formGroup]="formGroup">
      <ng-container formGroupName="profile">
        <div class="col-md-4 mb-4">
          <label for="firstname" class="form-label">First Name</label>
          <input
            type="text"
            class="form-control radius-none"
            formControlName="firstname"
            id="firstname"
          />
        </div>
      </ng-container>
      <p>Addresses</p>
      <ul formArrayName="addresses">
        <li *ngFor="let address of addresses.controls; let i = index">
          <div class="col-md-4 mb-4" [formGroupName]="i">
            <label for="idtype" class="form-label">ID type</label>
            <input
              type="text"
              class="form-control radius-none"
              formControlName="idtype"
              id="idtype"
            />
          </div>
        </li>
        <button type="button" (click)="addAddress.emit()">
          + Add another address
        </button>
      </ul>
    </div>
    

    Everything for this question I got from reactive forms doc https://angular.io/guide/reactive-forms