#typescript #angular-reactive-forms
#typescript #угловые-реактивные-формы
Вопрос:
У меня возникли проблемы с преобразованием объекта в formgroup. У меня есть инициализация моей формы. И у меня есть surveyData, объект той же структуры. Мне было интересно, как преобразовать значения моего объекта в FormGroup
surveyForm: FormGroup;
ngOnInit(): void {
this.surveyForm = this.formBuilder.group({
'surveyTitle': new FormControl(null, Validators.required),
'surveyDescription': new FormControl(null),
'questionsDetail': this.formBuilder.array([
this.formBuilder.group({
'questionType': new FormControl(null, Validators.required),
'question': new FormControl(null, Validators.required),
'choices': this.formBuilder.array([])
})
])
});
};
Я был бы очень признателен за помощь.
Заранее спасибо
Ответ №1:
Что вам нужно, так это немного рекурсии. Конечно, если вам не нравится рекурсия, вы всегда можете преобразовать ее в итерацию, но для нас, людей, рекурсию иногда легче понять.
constructor(private fb: FormBuilder) {
const data = {
email: 'test@email.com',
password: 'test-password',
address: [
{
street: 'Street 1',
postCode: 1000
},
{
street: null,
postCode: null
}
]
};
const validationSchema = {
email: [[Validators.required, Validators.email]],
password: [[Validators.required, Validators.minLength(6)]],
address: [
{
street: [[Validators.required]],
postCode: [[Validators.required]]
},
{
street: [[Validators.required]],
postCode: [[Validators.required]]
}
]
};
this.form = this.parseData(data, validationSchema) as FormGroup;
}
parseData(data: any, validators?: any): FormGroup | FormArray | [any, ValidatorFn[], AsyncValidatorFn[]] {
if (Array.isArray(data)) {
return this.fb.array(data.map((item, index) => this.parseData(item, (validators || {})[index])));
}
if (typeof data === 'object' amp;amp; data !== null) {
const formGroupContent = {};
for (const [key, value] of Object.entries(data)) {
formGroupContent[key] = this.parseData(value, (validators || {})[key]);
}
return this.fb.group(formGroupContent);
}
const [syncValidators = [], asyncValidators = []] = validators || [];
return [data, syncValidators, asyncValidators];
}
метод ParseData считывает объект данных и в зависимости от значения создает либо formArray
, formGroup
либо formControl
(но используя короткий синтаксис с и array — [value, syncValidators, asyncValidators] ). Здесь я предполагаю, что у вас где-то есть схемы проверки для каждой отдельной формы, но если вы храните их внутри самого объекта данных, используя строки или что-то еще, вы могли бы создать аналогичную функцию, которая создает схему проверки из объекта схемы, который вы получаете от серверной части.
Я провел некоторое время с динамической генерацией форм, и самое интересное начинается, когда вы начинаете подключать другой элемент формы внутри шаблона вашего компонента, потому что вам придется делать что-то подобное и там. Из того, что я помню, я использовал разные шаблоны для отдельного элемента формы, и я передавал родительский элемент внутри контекста шаблона, чтобы иметь возможность правильно все подключить.
Ответ №2:
У вас есть исходные данные? Похоже, вы это сделаете. Вы можете использовать подход, основанный на шаблонах angular, для сопоставления данных из объекта с ngModel
директивой в шаблоне.
<form #form>
<input type="text" [(ngModel)]="data.surveyTitle" required>
...
<input type="text" [(ngModel)]="data.questionsDetail.choices">
</form>
interface IData {
surveyTitle: string;
questionsDetail: {
...
choices: string;
}
}
@Component({...})
export MyComponent {
// for the reason if you need an entire form to get a status e.g dirty or access to the entire form data
// 'form' will be available in 'ngAfterViewInit' hook
@ViewChild('form', {static: true, read: NgForm})
form: NgForm
@Input()
data: IData
}
Комментарии:
1. Являются ли ключи в объекте динамическими? Если да, то это должен быть другой подход, аналогичный тому, что вы делаете прямо сейчас.