Как я могу преобразовать объект в Formgroup?

#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. Являются ли ключи в объекте динамическими? Если да, то это должен быть другой подход, аналогичный тому, что вы делаете прямо сейчас.