У меня есть компонент angular, который будет динамически создавать и отображать форму с помощью ReactiveFormsModule. Когда я нажму «Отправить», он опубликует данные, и я получу новые вопросы для компонента для рендеринга и замены старых.
Первый рендеринг проходит нормально, когда вы переходите на страницу. Если я отправлю первый вопрос, родитель получит новые вопросы для передачи этому компоненту.
эта ошибка: "There is no FormControl instance attached to form control element with name: 'q1124'
"
Всякий раз, когда я регистрирую form.controls, он говорит, что содержит «q1124».
форма.компонент.ts
import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { AbstractControl, FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { Question } from '../../../../shared/models/views-models/question-view';
import { getQuestionAnswers } from '../../../../shared/utils/helpers.util';
import { MatButtonModule } from '@angular/material/button';
import { MatCard } from '@angular/material/card';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
@Component({
selector: 'app-survey-form',
standalone: true,
imports: [FormsModule, ReactiveFormsModule, MatFormFieldModule, MatInputModule, MatCard, MatButtonModule,],
templateUrl: './survey-form.component.html',
styleUrl: './survey-form.component.scss'
})
export class SurveyFormComponent implements OnChanges {
form: FormGroup = new FormGroup({});
@Input() questions: Question[] = []
@Input() currentState: string | undefined;
@Input() previousState: string | undefined;
@Output() dataEmitter: EventEmitter<any[]> = new EventEmitter<any[]>();
constructor(private fb: FormBuilder, private cdr: ChangeDetectorRef) { }
ngOnChanges(changes: SimpleChanges): void {
if (changes['questions'] && changes['questions'].currentValue !== changes['questions'].previousValue) {
this.form = this.createForm(this.fb, this.questions)
this.cdr.detectChanges();
}
}
submit() {
if (this.form.valid) {
const answers = getQuestionAnswers(this.form, this.questions)
this.dataEmitter.emit(answers)
}
}
createForm = (
formBuilder: FormBuilder,
questions: any[]
): FormGroup => {
const group: { [key: string]: AbstractControl<any, any> } = {};
questions.forEach(question => {
group[question.id] = question.mandatory
? formBuilder.control('', [Validators.required])
: formBuilder.control('');
});
return new FormGroup(group)
}
}
форма.компонент.html
<div class = "form-container">
<form [formGroup] = "form" (ngSubmit) = "submit()" class = "input-form">
@for (question of questions; track $index) {
<input type = "text" matInput [formControlName] = "question.id" [required] = "question.mandatory"
placeholder = "Type your answer here..." [id] = "question.id">
}
@if (currentState) {
<button type = "submit" [disabled] = "form.invalid" mat-flat-button>Next</button>
}
</form>
</div>
Я пробовал разные перехватчики, такие как ngOnAfterInit, чтобы посмотреть, может ли это быть связано с каким-то временем, я также добавил ChangeDetectorRef.
ОБНОВЛЯТЬ Ссылка на Stackblitz с макетом https://stackblitz.com/edit/stackblitz-starters-4ewzry?file=src%2Fapp%2Fform-test%2Fform-test.comComponent.ts
🤔 А знаете ли вы, что...
Angular предоставляет средства для тестирования приложений, включая юнит-тестирование и интеграционное тестирование.
проблема в том, что вопросы имеют значения до создания формы
Вы можете перебирать form.controls|keyvalue
@for (control of form.controls|keyvalue; track $index) {
<!--see that you use questions[$index].id instead of question-->
<input type = "text" matInput [formControlName] = "questions[$index].id">
}
Но поймите, что вам нужно подождать, чтобы получить вопросы
ngOnChanges(changes: SimpleChanges): void {
if (
changes['questions'] &&
changes['questions'].currentValue !== changes['questions'].previousValue
) {
//enclosed in a setTimeout without "delay"
setTimeout(()=>{
this.form = this.createForm(this.fb, this.questions);
})
this.cdr.detectChanges();
}
}