title: Best way to retrieve form data from a nested component in an Angular project
body: <p>I'm working on an angular project that has the following situation: there is one component (ClientViewComponent) that contains:</p>
  
  <ul>
  <li>A summary of the whole client form in the form of labels (ClientOverviewComponent);</li>
  <li>Different "sub-forms" through which the user can switch between for edit (for simplicty, let's focus on only one, called ClientGeneralComponent);</li>
  </ul>
  
  <p>Only one of these sub-forms is displayed at a time for edit, but the overview displays the values of all the inputs in the sub-forms, in real time.</p>
  
  <p>So this is what exists now (simplified to only show parts of interest):</p>
  
  <p><strong>ClientViewComponent HTML</strong></p>
  
  <pre class="lang-html prettyprint-override"><code>    &lt;div class="container overview-container"&gt;
        &lt;h2&gt;Client Overview&lt;/h2&gt;
        &lt;client-overview
          [data]="clientOverviewData" 
          [generalGroup]="clientForm.controls['generalGroup']"
          (editFrame)="editFrame($event)"&gt;
        &lt;/client-overview&gt;
      &lt;/div&gt;
      &lt;div *ngIf="(currentFrame$ | async)" class="container part-container"&gt;
        &lt;h2&gt;Please choose: &lt;/h2&gt;  
        &lt;client-general 
          *ngIf="(currentFrame$ | async).code === 'general'" [data]="clientGeneralData" [formGroup]="clientForm.controls['generalGroup']"&gt;
        &lt;/client-general&gt;
      &lt;/div&gt; 
  </code></pre>
  
  <p><strong>ClientViewComponent TS</strong></p>
  
  <pre class="lang-js prettyprint-override"><code>ngOnInit() {
      this.clientForm = this.fb.group({
              generalGroup: this.fb.group({
                  name: ['', [Validators.required, Validators.maxLength(256)]], 
                  code: ['', [Validators.required, Validators.maxLength(32)]], 
                  addressGroup: this.fb.group({
                      address: ['', [Validators.required, Validators.maxLength(512)]],
                      address2: ['', [Validators.maxLength(512)]],
                      city: ['', [Validators.required, Validators.maxLength(256)]],
                      state: ['', [Validators.required, Validators.maxLength(64)]],
                      zipCode: ['', [Validators.required, Validators.maxLength(64)]],
                      country: ['', [Validators.required]],
                  })                
              })
          });
  }
  </code></pre>
  
  <p><strong>ClientOverviewHTML</strong></p>
  
  <pre class="lang-html prettyprint-override"><code>&lt;div class="span-container"&gt;
              &lt;span [ngClass]="{ 'modified-value' : !isNew &amp;&amp; generalGroup.controls['name'].dirty }"&gt;* Client Name: {{generalGroup.controls['name'].value}}&lt;/span&gt;
              &lt;span [ngClass]="{ 'modified-value' : !isNew &amp;&amp; generalGroup.controls['code'].dirty }"&gt;* Client Code: {{generalGroup.controls['code'].value}}&lt;/span&gt;
              &lt;span [ngClass]="{ 'modified-value' : !isNew &amp;&amp; addressGroup.controls['address'].dirty }"&gt;* Address: {{addressGroup.controls['address'].value}}&lt;/span&gt;        
              &lt;span [ngClass]="{ 'modified-value' : !isNew &amp;&amp; addressGroup.controls['address2'].dirty }"&gt;Address #2: {{addressGroup.controls['address2'].value}}&lt;/span&gt;        
              &lt;span [ngClass]="{ 'modified-value' : !isNew &amp;&amp; addressGroup.controls['city'].dirty }"&gt;* City: {{addressGroup.controls['city'].value}}&lt;/span&gt;        
              &lt;span [ngClass]="{ 'modified-value' : !isNew &amp;&amp; addressGroup.controls['state'].dirty }"&gt;* State: {{addressGroup.controls['state'].value}}&lt;/span&gt;        
              &lt;span [ngClass]="{ 'modified-value' : !isNew &amp;&amp; addressGroup.controls['country'].dirty }"&gt;* Country: {{country}}&lt;/span&gt;        
              &lt;span [ngClass]="{ 'modified-value' : !isNew &amp;&amp; addressGroup.controls['zipCode'].dirty }"&gt;* Zip Code: {{addressGroup.controls['zipCode'].value}}&lt;/span&gt;            
  &lt;/div&gt;
  </code></pre>
  
  <p><strong>ClientOverviewComponent TS</strong></p>
  
  <pre class="lang-js prettyprint-override"><code>export class ClientOverviewComponent implements OnInit {
  
      @Input('data')
      set Data(value: ClientOverviewData) {
          this.setData(value);
      }
  
      generalGroup: FormGroup;
      addressGroup: FormGroup;
      @Input('generalGroup') 
      set GeneralGroup(value: FormGroup) {
          this.generalGroup = value;
          this.addressGroup = value.get('addressGroup') as FormGroup;
          this.refreshClientValues();                
  }
  </code></pre>
  
  <p><em>The ClientGeneralComponent HTML is just a regular form with a formGroup and inputs with the corresponding formControlName</em></p>
  
  <p><strong>ClientGeneralComponent TS</strong></p>
  
  <pre class="lang-js prettyprint-override"><code>export class ClientGeneralComponent implements OnInit {
  
      @Input('data')
      set Data(value: ClientGeneralData) {
          this.setData(value);
      }
  
      formGroup: FormGroup;
      addressGroup: FormGroup;
      @Input('formGroup') 
      set FormGroup(value: FormGroup){
          this.formGroup = value;
          this.addressGroup = value.get('addressGroup') as FormGroup;
  }
  </code></pre>
  
  <p>Now, all this works fine. The complete form works as intended, the user fills in the inputs for the General component and the values are shown in the overview, in real time. The question rose when I started doing unit tests for the components. The problem is that, for the test class for the ClientGeneralComponent, I have to declare the form groups and controls again, the same way it's done in the ClientViewComponent code. My idea was that, if I could move the General form initialization from the ClientViewComponent to the ClientGeneralComponent (which actually contains the controls), there would be no need to copy the form init code in the test class, like this:</p>
  
  <pre class="lang-js prettyprint-override"><code>beforeEach(() =&gt; {
          fixture = TestBed.createComponent(ClientGeneralComponent);
          component = fixture.componentInstance;
          component.formGroup = fb.group({
              name: ['', [Validators.required, Validators.maxLength(256)]],
              code: ['', [Validators.required, Validators.maxLength(32)]],
              addressGroup: fb.group({
                  address: ['', [Validators.required, Validators.maxLength(512)]],
                  address2: ['', [Validators.maxLength(512)]],
                  city: ['', [Validators.required, Validators.maxLength(256)]],
                  state: ['', [Validators.required, Validators.maxLength(64)]],
                  zipCode: ['', [Validators.required, Validators.maxLength(64)]],
                  country: ['', [Validators.required]]
              })
          });
          fixture.detectChanges();
  });
  </code></pre>
  
  <p>But if I move the general form init code to the child form, I start getting "cannot read property of undefined" errors in the Overview component, since it didn't initialize the "generalGroup" property and its controls. So my question is if there is a way to do that, to initialize the form group in the child component where it belongs, and still be able to bind it in the parent form.</p>
  
  <p>Thanks for any help!</p>