Angular Reactive Forms, способ связывания объекта данных с каждым объектом FormArray - PullRequest
0 голосов
/ 08 марта 2019

Я строю реактивную форму, как показано на рисунке ниже -

Как показано на рисунке, у каждого файла (называемого вложения в коде) есть несколько повесток дня. Повестки дня могут быть добавлены, обновлены и удалены

enter image description here

buildForms() {
this.agendaForms = this.formBuilder.group({
  attachements: this.formBuilder.array([

  ])
});

Данные формы извлекаются из веб-службы, и модель формы создается таким образом-

data => {
    this.submission = data;

    // New blank agenda for all attachements
    if (
      !isNullOrUndefined(this.submission) &&
      !isNullOrUndefined(this.submission.attachments)
    ) {
      this.submission.attachments.forEach(attachment => {
        const agenda = new NLAgenda();
        agenda.dwgNo = attachment.filename;
        agenda.dWGNo = attachment.filename;
        this.submission.agendas.push(agenda);

        if (!isNullOrUndefined(attachment)) {
          attachment.agendas = this.getAgendasForAttachment(attachment);

          if (!isNullOrUndefined(attachment.agendas)) {
            this.attachmentFormArray = this.agendaForms.controls
              .attachements as FormArray;
            this.attachmentFormArray.push(
              this.createAttachmentAgendasControl(attachment.agendas)
            );
          }
        }
      });
    }
  }

Шаблоны выглядят примерно так

<form [formGroup]="agendaForms">
    <div formArrayName="attachements">
      <div *ngFor="let attachmentFormGroup of attachmentFormArray.controls;
          let attachmentId = index">

        <!-- Attachment header-->
        <div>
          <!-- File Name-->
          <div>
            {{ submission.attachments[attachmentId].filename }}
          </div>

          <!-- Action Buttons-->
          <div>
            <input type="button" value="Link To"/>
          </div>
        </div>

        <!-- Agendas -->
        <div formGroupName="{{ attachmentId }}">
          <div formArrayName="agendas">
            <div *ngFor="let agendaFormGroup of attachmentFormGroup.controls.agendas.controls;
                let agendaId = index">
              <div formGroupName="{{ agendaId }}" >
                <mat-form-field>
                  <input
                    type="text"
                    id="project"
                    placeholder="Sheet No."
                    formControlName="sheetNumber"
                    matInput
                  />
                  <!-- <mat-error>{{ getErrorMessage(f.project) }}</mat-error> -->
                </mat-form-field>
                <mat-form-field>
                  <input
                    type="text"
                    id="project"
                    placeholder="Title"
                    formControlName="title"
                    matInput
                  />
                </mat-form-field>
                <mat-form-field>
                  <input
                    type="text"
                    id="project"
                    placeholder="Description"
                    formControlName="description"
                    matInput
                  />
                </mat-form-field>

                <div>
                  <a
                    matTooltip="Add Agenda"
                    aria-label="Add Agenda"
                    (click)="
                      createOrUpdateAgenda(
                        submission.attachments[attachmentId].agendas[agendaId],
                        attachmentId,
                        agendaId
                      )">
                    <i class="fa fa-check"></i>
                  </a>
                  <a
                    *ngIf="submission.attachments[attachmentId].agendas[agendaId].created != null && submission.attachments[attachmentId].agendas[agendaId].created != undefined"
                    matTooltip="Delete Agenda"
                    aria-label="Delete Agenda"
                    (click)="deleteAgenda(submission.attachments[attachmentId].agendas[agendaId])">
                    <i class="fa fa-remove"></i>
                  </a>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </form>

Проблема: Всякий раз, когда повестки дня добавляются или обновляются, я перезагружаю данные объекта отправки с сервера, чтобы показать обновленное состояние файлов и повесток дня, объект отправки изменяется и выдает ошибки в консоли, такие как «Невозможно прочитать свойства« повестки дня »неопределенных», так как в новой позиции объекта отправки старые объекты изменяется из-за нового добавления или удаления

Я считаю, что мне нужно построить шаблон только с использованием одного массива (FormArray), а не двух массивов (массив форм и объект представления), иначе, если один из них будет изменен, пока консоль других изменений не выдаст ошибку. Но как использовать только FormArray, у меня есть некоторые данные в Submission Object? Есть ли способ связать объект отправки с FormArray?

Я устал https://github.com/angular/angular/issues/13845, но мне это не удалось, так как я использую построение форм и не знал, как сделать этот трюк с помощью построителя форм

1 Ответ

0 голосов
/ 18 марта 2019

Это проще, если вы сначала думаете о данных, которые вы получаете. Я думаю, что вы получите что-то вроде

[{filename:..,agenda:[
                     {sheetNumber:..,title:...,description...},
                     {sheetNumber:..,title:...,description...}
                          ...
                     ]
  },
  {filename:..,agenda:[
                     {sheetNumber:..,title:...,description...},
                     {sheetNumber:..,title:...,description...}
                          ...
                     ]
  }
  ....
]

Вы видите, что у вас есть FormArray (серия FormGroup), которая имеет два свойства: «имя файла» и «повестка дня» (Agenda - это новый FormArray)

объявить переменную как formArray

  form: FormArray

И создайте две функции.

createItemData(data):FormGroup
  {
    data=data|| {} as dataI;
    return new FormGroup(
      {
         filename:new FormControl(data.filename),
         agenda:new FormArray(data.agenda && data.agenda.length?
               data.agenda.map(agenda=>this.createAgendaSheet(agenda)):
               [])
      }
    )

  }
  createAgendaSheet(data):FormGroup{
    data=data|| {} as agendaI;
    return new FormGroup(
      {
        sheetNumber:new FormControl(data.sheetNumber),
        title:new FormControl(data.title),
        description:new FormControl(data.description),

      }
    )
  }

Посмотрите, как эти функции создают элемент массива. Я использую следующие два интерфейса, чтобы помочь мне создать форму

export interface agendaI {
  sheetNumber: number,
  title: string,
  desription: string
}
export interface dataI {
  filename: string,
  agenda: agendaI[]
}

Хорошо, будьте осторожны при создании формы:

<button (click)="addAgenda()">Add agenda</button>
<form *ngIf="form" [formGroup]="form">
    <!--form is a FormArray, so form.controls will be formGroup-->
    <div *ngFor="let control of form.controls;let i=index">
       <!--in this form group...-->
        <div [formGroup]="control">
            <!--we have a fromControl "filename"-->
            <input formControlName="filename"/><button (click)="add(i)">add</button>
      <!--and a FormArray "agenda"--->
      <div formArrayName="agenda">
        <div *ngFor="let c of control.get('agenda').controls;let j=index" >
          <div [formGroupName]="j">
            <input formControlName="sheetNumber">
            <input formControlName="title">
            <input formControlName="description">
            <button (click)="delete(i,j)">delete</button>
          </div>
        </div>
      </div>
    </div>
  </div>
</form>

Ну, последний шаг - создать функцию add, delete и addAgenda

addAgenda()
  {
    this.form.push(this.createItemData(null))
  }
  add(i)
  {
    (this.form.at(i).get('agenda') as FormArray).push(this.createAgendaSheet(null))
  }
  delete(i,j)
  {
    (this.form.at(i).get('agenda') as FormArray).removeAt(j)
  }

И, в ngOnInit создайте форму (я использовал константу "data")

 ngOnInit() {
    this.form=new FormArray(data.map(d=>this.createItemData(d)));
  }

Вы можете увидеть «уродливый» результат в stackblitz

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...