реактивная форма angular 6 с каскадными массивами

#angular #typescript #angular-reactive-forms

#angular #typescript #угловые реактивные формы

Вопрос:

Я тренируюсь с angular reactiveforms и создаю интерфейс, роль которого будет заключаться в подаче часто задаваемых вопросов. Первым уровнем формы будут темы, вторым — вопросы, а третьим — ряд шагов, которым необходимо следовать.

Хотя второй уровень соответствует первому, третий вызывает у меня боль. Терминал выводит как controls.registerOnChange is not a function , так и Cannot find control with path: 'questions -> steps' .

Я хотел бы понять, где и почему я совершаю ошибку.

мой компонент.ts

 import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, FormArray } from '@angular/forms'
import { ThemeService } from 'src/app/service/theme.service';

@Component({
  selector: 'app-edition-form',
  templateUrl: './edition-form.component.html',
  styleUrls: ['./edition-form.component.css']
})
export class EditionFormComponent implements OnInit {

  constructor(private fb:FormBuilder, private ts:ThemeService) { }
  form:FormGroup;
  themes;
  s_theme;
  questions;
  s_question;
  steps;
  s_step;
  msg;
  hitButton:string;

  ngOnInit() {
    this.s_theme==0;
    this.s_question=null;
    this.s_step=null;
    this.ts.getThemesList().subscribe(
      data => this.themes = data,
      err => this.msg = err
    )
    this.form = this.fb.group({
      id:'',
      libelle:'',
      //questions: this.fb.array([this.fb.control('')])
      questions: this.fb.array([this.initQuestion()])
    })

  }

  initQuestion(){
    return this.fb.group({
      id:'', libelle:'', steps: this.fb.array([this.initStep()])
    })
  }

  initStep(){
    return this.fb.group({
      id:'', libelle:'', path:''
    })
  }

  validateForm(){

  }


  // Définition d'un getter pour récupérer le tableau qu'on souhaite construire dans le formulaire
  get questionList(){
    return this.form.get('questions') as FormArray
  }

  get stepsList(){
    return this.form.get('questions').get('steps') as FormArray
  }

  // ajouter des contrôles dans les éléments de ce tableau
  addQuestion(){
    this.questionList.push(this.fb.control(''))
  }



  // sélection dans les listes déroulantes
  setTheme(theme){
    if(theme.libelle==null){
      this.s_theme = null;
      this.questions = null;
      this.removeControls(this.questionList)
    }else{
      this.s_theme = theme.id
    this.ts.getQuestions(theme.id).subscribe(
      data=> {
        this.questions = data
        this.removeControls(this.questionList)
        this.questions.forEach(element => {
          this.questionList.push(this.fb.control(element.libelle)) //permet de publier la liste des questions dans le formulaire
        });
      },
      err => this.msg = err
    )
    }
  }

  removeControls(list:FormArray){
    while(list.controls.length!==0){ //permet de supprimer des controles
      list.removeAt(0)
    }
  }

  setQuestion(question){
    this.s_question = question.id
    this.ts.getSteps(this.s_theme, question.id).subscribe(
      data => {
        this.steps = data

      },
      err=>this.msg=err
    )
    console.log(question)
  }

  setStep(step){
    this.s_step = step.id;
  }

  handleSubmit(formData){
    console.log(formData)
  }

  button(number){
    this.hitButton = number;
    if(this.hitButton=="01"){

    }else if(this.hitButton =="02"){
      this.addQuestion()
    }
    console.log(this.hitButton)
  }



}
  

Мой component.html

 <form [formGroup]=form (submit)=handleSubmit(this.form.value)>
  <div>
    <app-dropdown label="Thème" [list]="this.themes" (selection)="setTheme($event)"></app-dropdown>
  </div>
  <div *ngIf="this.s_theme==null">
    <p>ou</p>
    <input type="text" placeholder="Saisir nouveau thème" class="form-control" formControlName="libelle" />
  </div>

  <hr>
  <app-dropdown label="Questions" [list]="this.questions" (selection)="setQuestion($event)"></app-dropdown>
  <div>
    <div class="d-flex align-items-center">
      <div class="col-1">
        Ou
      </div>
      <div class="col-8">
        <app-bouton class="" id=02 text="Ajouter une question" (hit)=button($event)></app-bouton>
      </div>
    </div>
    <div formArrayName="questions">
      <div *ngFor="let question of questionList.controls; let i=index">
        <div class="row">
          <div class="col-1">
            <p>{{i 1}}</p>
          </div>
          <div class="col-8">
            <input type="text" class="form-control" placeholder="Saisissez votre question" [formControlName]="i" />
            <div formArrayName="steps">
              <div *ngFor="let step of questionList['controls'].steps['controls']; let j=index">
                <input type="text" class="form-control" placeholder="Saisissez votre étape" [formControlName]="j"/>
              </div>
            </div>

          </div>
        </div>
      </div>
      <hr>

    </div>
  </div>
  <hr>
  <button type="submit">Enregistrer</button>
</form>
  

Заранее благодарю вас за то, что помогаете мне прогрессировать.

Ответ №1:

Похоже, что steps выполняется поиск непосредственно под questions , а не в реальном.

Вы могли бы попробовать что-то вроде этого:

  <ng-container  [formGroup]="form.questions.get(i)">
                <div formArrayName="steps">
                <div *ngFor="let step of questionList['controls'].steps['controls']; let j=index">
                    <input type="text" class="form-control" placeholder="Saisissez votre étape" [formControlName]="j"/>
                </div>
                </div>
            </ng-container>
  

Я не совсем уверен в синтаксисе, но идея состоит в том, чтобы сообщить Angular, с каким вопросом он работает.