Reputation: 4626
I am working on a "Tasks" application in Angular 9 and PHP. I run into this a Cannot find control with name: <controll name>
error while trying to pre-populate the update form with data.
The form template:
<form [formGroup]="updateTask" name="edit_task_form">
<mat-form-field appearance="standard">
<mat-label>Title</mat-label>
<input matInput placeholder="Title" formControlName="title" placeholder="Title">
</mat-form-field>
<mat-form-field appearance="standard">
<mat-label>Short Description</mat-label>
<input matInput placeholder="Short description" formControlName="short-description" placeholder="Short Description">
</mat-form-field>
<mat-form-field>
<mat-label>Category</mat-label>
<mat-select formControlName="tags">
<mat-option *ngFor="let category of categories" [value]="category.id">{{category.name | titlecase}}</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="standard">
<mat-label>Full Description</mat-label>
<textarea matInput formControlName="full-description" placeholder="Full Description"></textarea>
</mat-form-field>
<div class="text-center">
<button mat-flat-button type="submit" color="accent" [disabled]="updateTask.pristine || updateTask.invalid">Update</button>
</div>
</form>
In the component's .ts file:
task_hash: string;
currentTask: any = {};
constructor(private _apiService: ApiService, private _formBuilder: FormBuilder, private _sharedService: SharedService) {}
updateTask = this._formBuilder.group({});
ngOnInit(): void {
this.task_hash = this._apiService.task_hash;
this._apiService.getTaskInfo().subscribe(res => {
this.currentTask = res;
const formInfo = this.currentTask.info;
formInfo.forEach(item => {
if (item.key === 'title' || item.key === 'short-description' || item.key === 'description' || item.key === 'tags') {
this.updateTask.addControl(item.key, this._formBuilder.control(item.data, item.key !== 'tags' ? Validators.required : null));
};
});
});
}
In the browser console, I get this error (for every form field): Cannot find control with name: 'title'
.
The cause of this problem seems to be the fact that, in another component I open the form in an Angular Material Dialog triggered by the click of a button:
<button mat-button color="primary" (click)="openForm($event, task.task_hash)">Open</button>
In the trigger's .ts file
openEditForm(event, task_hash): void {
event.stopPropagation();
// Dialog Configuration
const dialogConfig = new MatDialogConfig();
dialogConfig.width = '60%';
// Dialog Open
this._matDialog.open(TaskFormComponent, dialogConfig);
// Pass test_hash to API Service
this.apiService.test_hash = test_hash;
}
In order to make the dialog above work, I also added this in the TaskModule
entryComponents: [TestFormComponent];
But it seems that the dialog opens before the form is populated, which is the reason why the form never gets populated.
How can I fix this issue?
Upvotes: 0
Views: 637
Reputation: 584
I don't see any condition in template to block render of <form [formGroup]="updateTask" name="edit_task_form">
until this._apiService.getTaskInfo()
resolve a response, hence you get the error formControl not found.
add a flag inside getTaskInfo()
subscription
...
this._apiService.getTaskInfo().subscribe(res => {
...
this.formLoaded = true;
...
}
...
and in the template add
<form *ngIf="formLoaded" [formGroup]="updateTask" name="edit_task_form">
...
...
</form>
Find a demo code in stackblitz here (please don't mind the html, just copied from the question)
Upvotes: 1
Reputation: 11
Implement the ngAfterViewInit
interface on your component class:
@component
class AfterViewInitComponent implements AfterViewInit {
ngAfterViewInit: void {
this.task_hash = this._apiService.task_hash;
this._apiService.getTaskInfo().subscribe(res => {
this.currentTask = res;
const formInfo = this.currentTask.info;
formInfo.forEach(item => {
if (item.key === 'title' || item.key === 'short-description' || item.key === 'description' || item.key === 'tags') {
this.updateTask.addControl(item.key, this._formBuilder.control(item.data, item.key !== 'tags' ? Validators.required : null));
};
});
});
}
Upvotes: 1