Вывод динамической вложенной формы Angular 10 в таблицу html

#angular #html-table #nested #formarray

#angular #html-таблица #вложенный #formarray

Вопрос:

У меня есть угловая форма с динамической вложенной формой с использованием FormArray. Идею вложенной формы я почерпнул из другого поста. Я пытаюсь вывести вложенную форму в таблицу html с помощью rowspan. Я думаю, что структура разработана правильно, но когда я пытаюсь отобразить вложенную форму в таблицу, заголовок сдвигается вправо, и первый столбец становится столбцом для всего вывода.

Здесь у меня есть запись stackblitz:https://stackblitz.com/edit/angular-ivy-4zjniz?file=src/app/app.component.ts

При первом рендеринге формы отображается следующее: Первый раз на изображении компонента

Затем, когда я нажимаю Добавить место Emp и добавить навык, заголовок перемещается следующим образом.

Добавлены родительское и дочернее изображения

Как я могу заставить заголовок оставаться слева и правильно отображать таблицу? Заранее благодарю вас.

Вот мой HTML-код: (app.component.html )

 <div class="control-section e-rte-custom-tbar-section">
  <div >
    <form [formGroup]="empForm" (ngSubmit)="onSubmit()">
      <div formArrayName="employees">
        <table>
          <tr>
            <th rowspan="{rowSpan}">Emp #</th>
            <th rowspan="{rowSpan}">First</th>
            <th rowspan="{rowSpan}">Last</th>
            <th rowspan="{rowSpan}">Remove Emp Action</th>
            <th>Skill #</th>
            <th>Skill</th>
            <th>Exp</th>
            <th>Remove Skill Action</th>
          </tr>

          <ng-container *ngFor="let employee of employees().controls; let empIndex=index">  
            <tr [formGroupName]="empIndex">
              <td>{{empIndex}}</td>
              <td><input type="text" formControlName="firstName" placeholder="first"></td>
              <td><input type="text" formControlName="lastName" placeholder="last"></td>
              <td><button (click)="removeEmployee(empIndex)">Remove Emp</button></td>

              <div formArrayName="skills">
                <ng-container *ngFor="let skill of employeeSkills(empIndex).controls; let skillIndex=index">
                  <div [formGroupName]="skillIndex">
                    <tr>
                      <td>{{skillIndex}}</td>
                      <td><input type="text" formControlName="skill" placeholder="skill"></td>
                      <td><input type="text" formControlName="exp" placeholder="exp"></td>
                      <td><button (click)="removeEmployeeSkill(empIndex,skillIndex)">Remove Skill</button></td>
                    </tr>
                  </div>
                </ng-container>
                <tr><button type="button" (click)="addEmployeeSkill(empIndex)">Add Skill</button></tr>
              </div>
            </tr>
          </ng-container>
        </table>
      </div>
    
      <p>
        <button type="button" (click)="addEmployee()">Add Seat Emp</button>
      </p>
      <p>
        <button type="submit">Submit</button>
      </p>
    
    </form>
    
  </div>
</div>
  

Это код: (app.component.ts)

   import { Component, VERSION } from '@angular/core';
  import { FormGroup, FormArray, FormBuilder } from '@angular/forms'

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular '   VERSION.major;

  title = 'Nested FormArray Example Add Form Fields Dynamically';

  empForm:FormGroup;


  constructor(private fb:FormBuilder) {

    this.empForm=this.fb.group({
      employees: this.fb.array([]) ,
    })
  }


  employees(): FormArray {
    return this.empForm.get("employees") as FormArray
  }


  newEmployee(): FormGroup {
    return this.fb.group({
      firstName: '',
      lastName: '',
      skills:this.fb.array([])
    })
  }


  addEmployee() {
    console.log("Adding a employee");
    this.employees().push(this.newEmployee());
  }


  removeEmployee(empIndex:number) {
    this.employees().removeAt(empIndex);
  }


  employeeSkills(empIndex:number) : FormArray {
    return this.employees().at(empIndex).get("skills") as FormArray
  }

  newSkill(): FormGroup {
    return this.fb.group({
      skill: '',
      exp: '',
    })
  }

  addEmployeeSkill(empIndex:number) {
    this.employeeSkills(empIndex).push(this.newSkill());
  }

  removeEmployeeSkill(empIndex:number,skillIndex:number) {
    this.employeeSkills(empIndex).removeAt(skillIndex);
  }

  onSubmit() {
    console.log(this.empForm.value);
  }


}


export class country {
  id: string;
  name: string;

  constructor(id: string, name: string) {
    this.id = id;
    this.name = name;
  }
}
  

Ответ №1:

Эта строка:

 <div *ngFor="let employee of employees().controls; let empIndex=index">
  

нарушает разметку таблицы, потому что добавляет дополнительную div .

Вы можете изменить его на это:

 <ng-container *ngFor="let employee of employees().controls; let empIndex=index"> 
  

и тогда лишнее div не будет добавлено. Я попробовал это в вашем Stackblitz, и, похоже, теперь с этим изменением все работает нормально.

введите описание изображения здесь

Подробнее об Angular ngContainer читайте в документах Angular.

В глубине структуры возникает другая проблема, связанная с большим количеством div элементов, вложенных внутри таблицы. Вы можете заменить их все на ngContainer , это также работает для formArrayName и formGroupName . Но тогда возникает другая проблема вложенных tr элементов внутри tr элементов. Все вложенные элементы divs и tr являются недопустимым HTML для таблиц.

После замены всего div на ngContainer и удаления вложенного tr элемента возникает другая проблема.

введите описание изображения здесь

Итак, теперь, я думаю, вам, возможно, придется немного переосмыслить решение. Быстрой идеей может быть добавление вложенной таблицы для строк навыков. Теперь это выглядит так: введите описание изображения здесь

Может быть, это выглядит не так, как вам нужно, но теперь это, по крайней мере, допустимая таблица HTML, может быть, какой-нибудь CSS может улучшить ее внешний вид, если вы измените выравнивание ячеек данных сотрудника. Но я не думаю, что возможно иметь одну таблицу, которая будет отображать всех сотрудников и их навыки в одной таблице, я думаю, вам нужно будет использовать вложенную таблицу, как в моем примере, или придумать другое решение для этого.

Я разветвил ваш Stackblitz и добавил вложенную таблицу сюда.

Комментарии:

1. Привет, Натан. Спасибо за информацию о ng-контейнере. Я обновил код, чтобы использовать ng-container как для родительского, так и для дочернего FormArray. Родительский массив теперь правильно выровнен по заголовку, но дочерний массив занимает только первый столбец, а оставшийся дочерний столбец сдвинут вправо. Я обновил stackblitz с помощью обновленного кода и ссылок. stackblitz

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