0
votes

I have a big reactive form, and I want to break up the template into child components.

The child component is not pulling through default form data from Parent.

Initially I forgot to bind the child component formGroup attribute to the parent's FormGroup. I fixed this, put the issue persists.

I believe it may have something to do with dealing with nested FormGroups. I changed:

  <app-account-settings [formGroup]="settingsForm" [isBusiness]="isBusiness" 
   [user]="user"></app-account- 
   settings>

to:

  <app-account-settings [formGroup]="accountSettings" [isBusiness]="isBusiness" 
   [user]="user"></app-account- 
   settings>

This did not work.

Parent component:

export class SettingsPage implements OnInit {
  public user: any;
  public isBusiness: boolean;
  public settingsForm:  FormGroup


  constructor(
    private config: Configuration,
    private profileProvider: ProfileProvider,
    private authentication: AuthenticationProvider,
    private route: ActivatedRoute) {
  }

  ngOnInit() {
    this.isBusiness = this.authentication.isBusiness()
    this.user = this.route.snapshot.data.userProfile;

    this.settingsForm = new FormGroup({
      accountSettings: new FormGroup({
        username: new FormControl(this.user.username),
        email: new FormControl(this.user.email),
        password: new FormControl(this.user.password)
        })
           ...more form groups
      })

  })

Parent template:

<form [formGroup]="settingsForm" (ngSubmit)="onSubmit()">
   <app-account-settings [formGroup]="settingsForm" [isBusiness]="isBusiness" 
   [user]="user"></app-account- 
   settings>

Child component:

@Component({
  selector: 'app-account-settings',
  templateUrl: './account-settings.component.html',
  styleUrls: ['./account-settings.component.scss']
})
export class AccountSettingsComponent implements OnInit {
  @Input('isBusiness') isBusiness: boolean;
  @Input('user') user: any;
  @Input('id') id: any

  constructor(private controlContainer: ControlContainer) { }

  ngOnInit() {
   console.log('isBusiness', this.isBusiness) // successfully logs value
    console.log('user', this.user) // successfully logs value

  }

}

Child template:

<ng-container formGroup="controlContainer.control">
<div class="row settings-block">
  <div class="col-md-12" >
    <div class="box title">
      <div class="row" >
        <div class="col-md-12" >
          <h1>Account</h1>
        </div>
      </div>
    </div>
    <div class="box settings">
      <div class="row">
        <div class="col-md-4">
          <h1>Username</h1>
          <input type="text" placeholder="Username" formControlName="username" [value]="user.username">
        </div>
        <div class="col-md-4">
          <h1>Email Address</h1>
          <input type="email" placeholder="Email Address" formControlName="email" [value]="user.email || ''">
        </div>
        <div class="col-md-4">
          <h1>New Password</h1>
          <input type="password" placeholder="Enter New Password" formControlName="password" value="">
        </div>
    </div>
  </div>
</div>
</ng-container>

I expected that the default FormControl values to be passed through to the input elements of the child component. This does not happen.

2
Read about ControlValueAccessor,Ashish Ranjan

2 Answers

1
votes

Easiest way to solve this issue without implementing ControlValueAccessor is to use viewProviders on your child template.

Remove [formGroup]="settingsForm" from your <app-account-settings>

<form [formGroup]="settingsForm" (ngSubmit)="onSubmit()">
   <app-account-settings [isBusiness]="isBusiness" 
   [user]="user"></app-account-settings>

Then your child component add viewProviders property to component: (Don't need to inject ControlContainer on your constructor either, so you can remove it.)

@Component({
  selector: 'app-account-settings',
  templateUrl: './account-settings.component.html',
  styleUrls: ['./account-settings.component.scss'],
  viewProviders: [ { provide: ControlContainer, useExisting: FormGroupDirective }]
})

Then you can just use your formGroup="accountSettings" on your child components

Here's an example on stackblitz for reference: https://stackblitz.com/edit/angular-ruxfee

0
votes

Try changing <ng-container formGroup="controlContainer.control"> to <ng-container [formGroup]="controlContainer.control">. When you are specifying an attribute with square brackets (Property binding), Angular interprets the right side as JS object, but when you don't use them, angular is not evaluating it and thinks it's just a string.