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>