title: Don't show FormArray if it is empty or undefined in a Reactive Form
body: <p>I've just started to learn Angular 4 doing my first project.</p>
  
  <p>I have created a Reactive Form to show a form with the following structure:</p>
  
  <pre><code>Form (FormGroup)
    |
    --&gt; aggLevels (FormArray)
         |
         --&gt; aggregationLevelName (FormControl? I show it in a label)
         |
         --&gt; variableDataForLevel (FormArray)
              |
              --&gt; variableDataId (FormControl)
              |
              --&gt; value (FormControl)
  </code></pre>
  
  <p>This is the component HTML:</p>
  
  <pre><code>&lt;form [formGroup]="varDataForm" (ngSubmit)="onSubmit()" novalidate&gt;
      &lt;div formArrayName="aggLevels"
           *ngFor="let agLevel of varDataForm.get('aggLevels')?.controls; let aggLevelId = index;"&gt;
          &lt;div [formGroupName]="aggLevelId"&gt;
              &lt;label&gt;{{agLevel?.get('aggregationLevelName')?.value}}&lt;/label&gt;
              &lt;div formArrayName="variableDataForLevel"
                   *ngFor="let vardata of varDataForm.get('aggLevels')?.controls[0]?.get('variableDataForLevel')?.controls; let rowIndex = index;"&gt;
                  &lt;div [formGroupName]="rowIndex"&gt;
                      &lt;select formControlName="variableDataId"&gt;
                          &lt;option *ngFor="let gs1 of gs1AIs" [value]="gs1.Id"&gt;{{gs1.description}}&lt;/option&gt;
                      &lt;/select&gt;
                      &lt;input formControlName="value" placeholder="Valor"&gt;
                      &lt;div class="error" *ngIf="vardata.get('value').hasError('required') &amp;&amp; vardata.get('value').touched"&gt;
                          Obligatorio
                      &lt;/div&gt;
                  &lt;/div&gt;
              &lt;/div&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  &lt;/form&gt;
  </code></pre>
  
  <p>My problem here is when there isn't any element in <code>variableDataForLevel</code> FormArray. I get this message:</p>
  
  <blockquote>
    <p>ng:///AppModuleShared/VarDataComponent.ngfactory.js:49 ERROR Error:
    Cannot find control with path: 'aggLevels -> 1 -> variableDataForLevel
    -> 0'</p>
  </blockquote>
  
  <p>I have tried to add safe navigation operator <code>?</code> at the end of all elements:</p>
  
  <pre><code>varDataForm.get('aggLevels')?.controls[0]?.get('variableDataForLevel')?.controls
  </code></pre>
  
  <p>But I still get the problem. FormArray <code>aggLevels</code> and <code>variableDataForLevel</code> aren't undefined because when I create it I instance it.</p>
  
  <p>What can I do to don't show the FormArray if is empty?</p>
  
  <p>I new with Angular and I have few knowledge about how to fix it.</p>
  
  <p>This is the component typescript class for this component:</p>
  
  <pre><code>import { Component, Inject } from '@angular/core';
  import { FormBuilder, FormGroup, FormArray, FormControl, Validators } from '@angular/forms';
  import { Http, RequestOptions, Headers } from '@angular/http';
  import { IProductionOrder } from '../../interfaces/productionorder.interface';
  import { IAggLevel } from '../../interfaces/aglevel.interface';
  import { IGS1 } from '../../interfaces/gs1.interface';
  import { IVarData } from '../../interfaces/vardata.interface';
  
  @Component({
      selector: 'vardata',
      templateUrl: './vardata.component.html'
  })
  
  export class VarDataComponent {
      public productionorders: IProductionOrder[];
      public gs1AIs: IGS1[];
  
      public varDataForm: FormGroup = new FormGroup({});
      public selectedProductionOrder: string;
  
      constructor(private http: Http,
          @Inject('BASE_URL') private baseUrl: string,
          @Inject(FormBuilder) private fb: FormBuilder) {
  
          this.selectedProductionOrder = '';
  
          http.get(baseUrl + 'api/ProductionOrder/0').subscribe(result =&gt; {
              this.productionorders = result.json() as IProductionOrder[];
  
              console.log(this.productionorders);
          }, error =&gt; console.error(error));
      }
  
      productionOrderChanges() {
          if (this.selectedProductionOrder != '') {
              let urlVarData: string = this.baseUrl + 'api/VariableData/' + this.selectedProductionOrder;
              let urlAggLevel: string = this.baseUrl + 'api/AggregationLevelConfiguration/' + this.selectedProductionOrder;
  
              this.http.get(urlAggLevel).subscribe(result =&gt; {
                  let aggLevels: IAggLevel[] = result.json() as IAggLevel[];
  
                  console.log('niveles');
                  console.log(aggLevels);
  
                  if ((aggLevels != null) &amp;&amp; (aggLevels.length &gt; 0)) {
  
                      this.http.get(urlVarData).subscribe(result =&gt; {
                          let varDatas: IVarData[] = result.json() as IVarData[];
  
                          console.log('variable data');
                          console.log(varDatas);
  
                          this.varDataForm = this.fb.group({
                              aggLevels: this.fb.array(this.createForm(aggLevels, varDatas))
                          });
  
                      }, error =&gt; console.error(error));
                  }
  
              }, error =&gt; console.error(error));
          }
          else
              this.varDataForm = new FormGroup({});
      }
  
      createForm(aggLevels: IAggLevel[], varDatas: IVarData[]): any[] {
          let array: any[] = [];
  
          for (let level of aggLevels) {
              let group: FormGroup;
              let varDataForLevel: IVarData[] =
                  varDatas.filter(v =&gt; v.aggregationLevelConfigurationId == level.aggregationLevelConfigurationId);
  
              group = this.createFormGroupForLevel(level, varDataForLevel);
              array.push(group);
          }
  
          return array;
      }
  
      createFormGroupForLevel(level: IAggLevel, varDatas: IVarData[]): FormGroup {
          let group: FormGroup;
  
          group = this.fb.group({
              aggregationLevelName: level.name,
              variableDataForLevel: this.fb.array(this.createVarDataControls(varDatas))
          });
  
          return group;
      }
  
      createVarDataControls(varData: IVarData[]): any[] {
          let array: any[] = [];
  
          for (let vData of varData) {
              let group: FormGroup;
  
              group = this.fb.group({
                  variableDataId: vData.variableDataId,
                  value: vData.value
              });
  
              array.push(group);
          }
  
          return array;
      }
  
  
  
      disableSubmit() {
          return (!this.varDataForm.valid);
      }
  
      onSubmit() {
      }
  }
  </code></pre>
  
  <p>I think the problem is here:</p>
  
  <pre><code>createVarDataControls(varData: IVarData[]): any[] {
      let array: any[] = [];
  
      for (let vData of varData) {
          let group: FormGroup;
  
          group = this.fb.group({
              variableDataId: vData.variableDataId,
              value: vData.value
          });
  
          array.push(group);
      }
  
      return array;
  }
  </code></pre>
  
  <p>if <code>varData</code> is empty it will return a <code>Any[]</code>, but I don't think return this is an error because I don't want to show something empty on the form.</p>
  
  <p>I have edited method <code>createVarDataControls</code> to return a <code>FormGroup</code> if <code>varData</code> is empty. This let me continue but I don't think it answers my question:</p>
  
  <pre><code>createVarDataControls(varData: IVarData[]): any[] {
      let array: any[] = [];
  
      if ((varData == null) || (varData.length == 0)) {
          let group: FormGroup;
  
          group = this.fb.group({
              variableDataId: '',
              value: ''
          });
  
          array.push(group);
      }
      else {
          for (let vData of varData) {
              let group: FormGroup;
  
              group = this.fb.group({
                  variableDataId: vData.variableDataId,
                  value: vData.value
              });
  
              array.push(group);
          }
      }
  
      return array;
  }
  </code></pre>
  
  <p>With it I don't get any exception but it shows two empty controls, and I don't want that. This is only useful to identify the problem.</p>