0

I have two Angular components. One is called web-services and another is called web-service. I am hosting a web-service on the template page of web-services and attempting to bind to its service property via the @Input() decorator that I am importing from @angular/core. However, whenever a web service is selected, I'm getting an error message of 'Cannot read property controls of undefined' which seems to be a problem with my web-service.component.html when it accesses inputParameters.controls. I've printed inputParameters.controls to the console after it's been set and both name and type are definitely there as form controls. Am I accessing them incorrectly some how in the HTML?

web-services.component.ts

export class WebServicesComponent implements OnInit {
  services: Observable<WebService[]>;
  isLoading = false;
  selectedService: WebService;

  constructor(private webServicesService: WebServicesService) { }

  ngOnInit() {
    this.getServices();
  }

  getServices() {
    this.isLoading = true;
    this.services = this.webServicesService.getWebServices()
      .finally(() => this.isLoading = false);
    this.selectedService = undefined;
  }

  selected(service: WebService) {
    this.selectedService = service;
  }

}

web-services.component.html

<h3 *ngIf="isLoading"><i>Loading services ... </i></h3>
<h3 *ngIf="!isLoading && !selectedService">Select a service:</h3>

<ul class="ms-List" *ngIf="!selectedService">
    <li class="ms-ListItem" tabindex="0" *ngFor="let service of services | async">
        <span class="ms-ListItem-primaryText">{{service.name}}</span> 
        <span class="ms-ListItem-secondaryText">{{service.description}}</span> 
        <span class="ms-ListItem-tertiaryText">{{service.version}}</span> 
        <span class="ms-ListItem-metaText">{{service.creationTime}}</span> 
        <a class="ms-Link" (click)="selected(service)">Select</a> 
    </li>
</ul>

<div *ngIf="selectedService">
    <app-web-service [service]="selectedService"></app-web-service>
</div>

web-service.component.ts

export class WebServiceComponent implements OnInit {
  @Input() service: WebService;

  serviceForm: FormGroup;

  constructor(private fb: FormBuilder, private excelService: ExcelService) { 
    this.createForm();
  }

  ngOnInit() {

  }

  createForm() {
    this.serviceForm = this.fb.group({
      inputParameters: this.fb.array([]),
      outputParameters: this.fb.array([])
    });
  }

  ngOnChanges() {
    this.setParameters()
  }

  setParameters() {
    console.log(this.service.inputParameterDefinitions);
    const inputParameters = this.service.inputParameterDefinitions.map(input => this.fb.group(input));
    const inputParametersFormArray = this.fb.array(inputParameters);
    this.serviceForm.setControl('inputParameters', inputParametersFormArray);

    console.log(this.serviceForm.controls);

    const outputParameters = this.service.outputParameterDefinitions.map(output => this.fb.group(output));
    const outputParametersFormArray = this.fb.array(outputParameters);
    this.serviceForm.setControl('outputParameters', outputParametersFormArray);
  }

web-service.component.html

<form [formGroup]="serviceForm" (ngSubmit)="onSubmit()" novalidate>
    <!-- Service Controls -->
    <div formArrayName="inputParameters">
        <div *ngFor="let parameter of inputParameters.controls; let i=index" [formGroupName]="i">
            <!--The repeated parameter template-->
            <div>
                <label>Name:
                    <input formControlName="name">
                </label>
            </div>
            <div>
                <label>Type:
                    <input formControlName="type">
                </label>
            </div>
        </div>
    </div>
</form>

1 Answer 1

1

try to test if your service is not null before setting parameters :

ngOnChanges(changes: {[ propName: string]: SimpleChange}) {
        if(changes[service].currentValue)
              this.setParameters();
}

hope it helps you :)

Sign up to request clarification or add additional context in comments.

3 Comments

Yeah, I've checked the service and it isn't null. It is successfully being passed through property binding. Am I accessing it incorrectly in the html?
can you try : <div *ngFor="let parameter of serviceForm.controls['inputParameters'].controls; let i=index" [formGroupName]="i">
That worked! Thank you! Why do I need to reaccess the serviceForm when I'm already stating that the formGroup is the service form and the formArrayName is inputParameters?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.