Search code examples
angularangular-forms

cannot find path to control angular 13.0.0 with TS


I know it's been asked but I seem to have it set up right and still have an error with my angular form.

Cannot find control with path: 'builderPreferences -> idx -> groupId' and Cannot find control with path: 'builderPreferences -> idx -> manufacturerId'

I have the form group and array builder in TS as such:

@Component({
  selector: 'app-builder-detail',
  templateUrl: './builder-detail.component.html',
  styleUrls: ['./builder-detail.component.scss']
})
export class BuilderDetailComponent implements OnInit {
  builderId?: number;
  groups?: any[];
  manufacturers?: any[];
  builder = this.formBuilder.group({
      name: ['', Validators.required],
      builderPreferences: this.formBuilder.array([]),
  });



  get builderPreferences(): UntypedFormArray {
    return this.builder.get('builderPreferences') as UntypedFormArray;
  }



  deletePreference(index: number) {
    this.builderPreferences.removeAt(index);
  }

  constructor(
    @Optional() @Inject(API_VERSION) private apiVersion: string,
    public modalRef: BsModalRef,
    private formBuilder: UntypedFormBuilder,
    private buildersApiService: BuildersApiService,
    private groupsApiService: GroupsApiService,
    private manufacturersApiService: ManufacturersApiService,
    private loader: LoadingService
  ) {}

  ngOnInit() {
    if (this.builderId) this.loadDetail();
  }

  async loadDetail() {
    let builder = await this.buildersApiService.Get({
      path: {
        version: this.apiVersion,
        id: this.builderId ?? 0
      }
    }).toPromise();

    this.builder.patchValue(builder);

    if (builder.builderPreferences) {
      let processedPreferences = this.formBuilder.array([]);

    for (let idx = 0; idx < builder.builderPreferences.length; idx++) {
       
  processedPreferences.push(this.formBuilder.group(builder.builderPreferences[idx]))
  }

  this.builder.setControl('builderPreferences', processedPreferences);
 }
}

 newPreference() {
   this.builderPreferences.push(this.formBuilder.group({
     groupId: [],
  manufacturerId: [], 
 }));
}


async save(close: boolean = false) {
this.loader.start();
let call;

if (this.builderId) {
  call = await this.buildersApiService.Update({
    body: this.builder.value,
    path: {
      version: this.apiVersion,
      id: this.builderId ?? 0
    }
  }).toPromise();
 } else {
  call = await this.buildersApiService.Create({
    body: this.builder.value,
    path: {version: this.apiVersion}
  }).toPromise();
  }

    this.builder.markAsPristine();
    this.loader.stop();

    if (!this.builderId) this.builderId = call.id;
  }
}

And the html file is as such:

<form autocomplete="off" [formGroup]="builder">
  <div class="col-md-12">
   <div class="row g-3">
    <div class="col-12">
     <label class="form-label" for="name">Name</label>
     <input formControlName="name" id="name" type="text" class="form-control">
    </div>
   </div>

<div class="section back-charges">
  <h4>Preferences</h4>
   <ul class="amount-list" *ngIf="builderPreferences?.length" 
    formArrayName="builderPreferences" >
     <li *ngFor="let builderPreference of builderPreferences.controls; let idx = index">  
       <div class="row g-3" formGroupName="idx">
        <div class="col-3">
         <select formControlName="groupId" class="form-control mb-3">
           <option value="undefined" selected>Select Group</option>
            <option *ngFor="let group of groups"
              value="{{ group.id }}">
              {{ group.name }}
            </option>
        </select>
      </div>
      <div class="col-3">
        <select formControlName="manufacturerId" class="form-control mb-3">
          <option value="undefined" selected>-- Select Manufacturer / Division -- 
           </option>
          <option *ngFor="let manufacturer of manufacturers"
              value="{{ manufacturer.id }}">
              {{ manufacturer.name }}
          </option>
        </select>
      </div>
      <div class="col-1">
        <button type="button" name="delete" class="btn btn-text" 
        (click)="deletePreference(idx)">
            <i class="fa fa-trash"></i>
          </button>
        </div>         
      </div>
    </li>
  </ul> 
  <button class="btn btn-link" type="button" (click)="newPreference()">
    <i class="fa fa-plus"></i> Add Preference
  </button>
</div>
</div>
</form>

Solution

  • Found the error when looking at this link - looks like I was missing some binding!

    https://dontpaniclabs.com/blog/post/2022/01/05/how-to-use-angular-formarrays-within-formgroups-in-reactive-forms/

    swapped the ul from formArrayName to [formArrayName]

      <ul class="amount-list" *ngIf="builderPreferences?.length" 
        [formArrayName]="builderPreferences" >
    

    and the option to this:

    <option *ngFor="let group of groups"
       [ngValue]="group.id">
          {{ group.name }}
    </option>