0

I'm trying to implement a reactive Angular form, but, I can't access the properties of the array on HTML, I never worked with reactive form, if anyone could guide me I would be grateful! I'm using Angular 10 and I have the following code:

TS

operationModel: IScriptOperationsModel;
formOperation: FormGroup;

constructor(
  private fb: FormBuilder,
  ...
) {}

ngOnInit() {
  this.operationModel = new IScriptOperationsModel();
  this.operationModel.scriptOperationOrders = [];
  this.buildForm(new IScriptOperationsModel());

  this.scriptOperationsService.findScriptOperation(this.operationId).subscribe((operation) => {
    this.operationModel = operation.data as IScriptOperationsModel;  // api return
    this.buildForm(this.operationModel);  // I pass the return of the api to the form
  });
}

buildForm(operation: IScriptOperationsModel) {
  this.formOperation = this.fb.group({
    descriptionCode: [operation.descriptionCode],
    description: [operation.description],
    workStations: this.fb.array([])
  });
  this.formOperation.setControl('workStations', this.fb.array(this.operationModel.scriptOperationOrders));
}

get workStations(): FormArray {
  return this.formOperation.get('workStations') as FormArray;
}

HTML

<div
  class="card"
  [ngClass]="{'bg-principal': idx === 0, 'bg-alternative': idx !== 0}"
  formArrayName="workStations"
  *ngFor="let workstation of workStations.controls; index as idx"
>
  <div class="card-body" [formGroupName]="idx">
    <div class="form-row">
      <div class="form-group col-md-1">
        <label>Id Oper.</label>
        <input
          type="text"
          name="idOperation"
          class="form-control"
          disabled
          formControlName="rank"            <!-- whatever with or without binding gives error -->
        />
      </div>
      <div class="form-group col-md-2">
        <label>Time</label>
        <input
          type="time" class="form-control" name="defaultTime"
          [formControlName]="defaultTime"   <!-- whatever with or without binding gives error -->
        />
      </div>
    </div>
  </div>
</div>

Models

export class IScriptOperationsModel extends Serializable {
  public description: string;
  public descriptionCode: string;
  public scriptOperationOrders: IScriptOperationOrdersModel[];     // array which I need
}

export class IScriptOperationOrdersModel extends Serializable {
  public rank: number;
  public defaultTime: string;
  public asset?: IAssetModel;
  public provider?: IProviderModel;
}

error-handler.service.ts:87 Error: Cannot find control with path: 'workStations -> 0 -> rank' @ undefined:undefined

NOTE: I already looked at some answers here on the site such as this, this and this , but none of them solved this problem!

LeAndrade
  • 138
  • 1
  • 9

1 Answers1

2

your problem is here :

this.formOperation.setControl(
'workStations',
this.fb.array(this.operationModel.scriptOperationOrders) <== here the problem
);

you are passing an array of IScriptOperationOrdersModel instead of array of form group.
To make your code working, you have to loop on every element of this.operationModel.scriptOperationOrders array , and instanciate a new FormControl object then push it in the workStations form array.
To access its elements, you can use controls[indexOfGroup].rate

You can take a look at this simple example you will understand everything.

sohaieb azaiez
  • 768
  • 9
  • 20
  • Thanks for answering man, ok to add form fields on the screen it worked, now my question is as follows, how could I integrate this form with an API, like the first time the user accesses the page there will be nothing and it will adding normally, but, as it would be the second time the user accesses the screen, how would it show the ones that have already been added previously? – LeAndrade Mar 12 '21 at 21:37
  • 1
    you are welcome:) To be honest, i did not understand exactly your second point, do you mean : what if you want to edit your added entities previously with the same formGroup and formArray, right? – sohaieb azaiez Mar 13 '21 at 09:55
  • Exactly, how for example do I build the form with an array coming from the API, with data in the same format as the ones informed but coming from the backend? It was exactly at that point in your reply that you said it would be wrong: `this.fb.array (this.operationModel.scriptOperationOrders)` – LeAndrade Mar 13 '21 at 13:01
  • In that case, you have to follow the same logic as my solution above but by making some changes on your **IScriptOperationOrdersModel** class by adding an "id" field which we will use for update process for each updated elemnt. But when you want to retreive data from your backend API, then you should just build your form controls as i mentioned above, then set data gotten by **.subscribe(..)** method to the built controls using it's indexes.. if this did not help or if something is not clear, it would be nice if you reproduce your code using [stackblitz.com](http://stackblitz.com/] – sohaieb azaiez Mar 13 '21 at 13:37