Как добавить значения из массива в форму?

При нажатии на «Редактировать задачу» открывается форма, которая уже содержит значения задачи. Это уже работает для простых строк, но не для значений, имеющих массив значений.

Проблема:

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

Я уже исследовал, но не смог реализовать решение в своем коде:

patchValue для объекта FormArray?

Как использовать FormArray в angular

Демо-версия Stackblitz:

https://stackblitz.com/edit/stackblitz-starters-1ksmca?file=src%2Fmain.ts

Самый актуальный код:

ts-файл:

export class TaskFormComponent {
  protected readonly Object = Object;
  taskForm!: FormGroup;
  fromPopup = false;

  constructor(
    @Optional()
    @Inject(MAT_DIALOG_DATA)
    public data: { fromPopup: boolean; task: Task }
  ) {}

  ngOnInit() {
    this.fromPopup = !!this.data?.fromPopup;
    this.taskForm = new FormGroup({
      assignedTo: new FormControl(''),
    });

    if (this.data?.task) {
      this.taskForm.setValue({
        assignedTo: this.data.task.contacts,
      });
    }
  }

  public onSubmit() {
    console.info('Submitted');
  }
}

html-файл:

<div>
  <div>
    <div mat-dialog-title>Edit Task</div>
  </div>

  <mat-dialog-content>
    <form [formGroup] = "taskForm" (ngSubmit) = "onSubmit()">
      <mat-form-field>
        <mat-label>Assigned to</mat-label>
        <mat-icon color = "primary" matSuffix>group_add</mat-icon>
        <mat-select formControlName = "assignedTo" multiple>
          @for (contact of this.data.task.contacts; track contact.id) {
          <mat-option [value] = "contact.id">{{ contact.name }}</mat-option>
          }
        </mat-select>
      </mat-form-field>
    </form>
  </mat-dialog-content>

  <mat-dialog-actions>
    <button mat-raised-button color = "primary" type = "submit">
      {{ data?.task ? 'Update Task' : 'Create Task' }}
    </button>
    <button mat-raised-button mat-dialog-close type = "button" color = "warn">
      Close
    </button>
  </mat-dialog-actions>
</div>

Сейчас ваш вопрос слишком широк. Это звучит как «реализуйте этот код для меня», что не по теме этого сайта. Если это не ваше намерение и у вас есть конкретный вопрос о целевой части вашего решения, вам следует отредактировать свой вопрос, чтобы было ясно, что это такое.

bob 16.05.2024 03:13
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
0
1
63
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вопрос может показаться слишком широким, но я постараюсь ответить, сосредоточив внимание на первоначальном вопросе. Один из способов получить доступ к значению массива в HTML — перебрать переменную с помощью NgFor, например:

<ul>
  <li *ngFor = "let item of items">{{ item }}</li>
</ul>

Если это ответ на вопрос ОП (и я не говорю, что это не так), то этот вопрос должен быть дубликатом; не может быть, чтобы этот вопрос еще не был задан и на него не был дан ответ на этом сайте.

bob 16.05.2024 07:10

Поскольку ОП спрашивает о формах, возможно, пример API FormArray будет лучшим предложением?

alcfeoh 17.05.2024 21:23
Ответ принят как подходящий

Поскольку вы установили значение параметров выбора в поле id.

...
<mat-option [value] = "contact.id">{{ contact.name }}</mat-option>
...

Мы также должны использовать patchValue для идентификаторов как массива, для этого мы используем оператор карты javascript, чтобы получить только идентификаторы из массива объектов!

...
if (this.data?.task) {
  this.taskForm.setValue({
    assignedTo: this.data.task.contacts.map((x) => x.id),
  });
}
...

ПОЛНЫЙ КОД:

ТС

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Inject, Optional } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckbox } from '@angular/material/checkbox';
import {
  MatError,
  MatFormField,
  MatFormFieldModule,
  MatLabel,
} from '@angular/material/form-field';
import {
  FormControl,
  FormGroup,
  ReactiveFormsModule,
  Validators,
} from '@angular/forms';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatInputModule } from '@angular/material/input';
import { MatOption, provideNativeDateAdapter } from '@angular/material/core';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { TitleCasePipe } from '@angular/common';
import { MatSelect } from '@angular/material/select';
import { MatIconModule } from '@angular/material/icon';
import { MatRadioButton, MatRadioGroup } from '@angular/material/radio';
import {
  MAT_DIALOG_DATA,
  MatDialog,
  MatDialogModule,
  MatDialogRef,
} from '@angular/material/dialog';
import { Task } from '../../app/task';

@Component({
  selector: 'app-task-form',
  standalone: true,
  imports: [
    CommonModule,
    MatButtonModule,
    MatCheckbox,
    MatError,
    MatFormField,
    MatLabel,
    ReactiveFormsModule,
    MatDatepickerModule,
    MatInputModule,
    MatFormFieldModule,
    MatButtonToggleModule,
    TitleCasePipe,
    MatSelect,
    MatOption,
    MatRadioGroup,
    MatRadioButton,
    MatDialogModule,
    MatIconModule,
  ],
  templateUrl: './task-form.component.html',
  styleUrl: './task-form.component.css',
})
export class TaskFormComponent {
  protected readonly Object = Object;
  taskForm!: FormGroup;
  fromPopup = false;

  constructor(
    @Optional()
    @Inject(MAT_DIALOG_DATA)
    public data: { fromPopup: boolean; task: Task }
  ) {}

  ngOnInit() {
    this.fromPopup = !!this.data?.fromPopup;
    this.taskForm = new FormGroup({
      assignedTo: new FormControl(''),
    });

    if (this.data?.task) {
      this.taskForm.setValue({
        assignedTo: this.data.task.contacts.map((x) => x.id),
      });
    }
  }

  public onSubmit() {
    console.info('Submitted');
  }
}

HTML

<div>
  <div>
    <div mat-dialog-title>Edit Task</div>
  </div>

  <mat-dialog-content>
    <form [formGroup] = "taskForm" (ngSubmit) = "onSubmit()">
      <mat-form-field>
        <mat-label>Assigned to</mat-label>
        <mat-icon color = "primary" matSuffix>group_add</mat-icon>
        <mat-select formControlName = "assignedTo" multiple>
          @for (contact of this.data.task.contacts; track contact.id) {
          <mat-option [value] = "contact.id">{{ contact.name }}</mat-option>
          }
        </mat-select>
      </mat-form-field>
    </form>
  </mat-dialog-content>

  <mat-dialog-actions>
    <button mat-raised-button color = "primary" type = "submit">
      {{ data?.task ? 'Update Task' : 'Create Task' }}
    </button>
    <button mat-raised-button mat-dialog-close type = "button" color = "warn">
      Close
    </button>
  </mat-dialog-actions>
</div>

РОДИТЕЛЬ:

import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { TaskFormComponent } from './app/task-form/task-form.component';
import { filter } from 'rxjs';
import 'zone.js';
import { MatDialog } from '@angular/material/dialog';
import { Task } from './app/task';
import { provideAnimations } from '@angular/platform-browser/animations';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [TaskFormComponent],
  template: `
    <button (click) = "editTask()">Edit Task</button>
  `,
})
export class App {
  name = 'Angular';

  constructor(private dialog: MatDialog) {}

  public editTask() {
    let task: Task = {
      id: 1,
      contacts: [
        {
          id: 1,
          name: 'John Doe',
        },
        {
          id: 2,
          name: 'Jane Doe',
        },
      ],
    };
    this.dialog
      .open(TaskFormComponent, {
        data: { fromPopup: true, task: task },
      })
      .afterClosed()
      .pipe(filter((task) => task))
      .subscribe((task) => {
        console.info('Edit Task');
      });
  }
}

bootstrapApplication(App, {
  providers: [provideAnimations()],
}).catch((err) => console.error(err));

Демо-версия Stackblitz

Я думал, что вы могли бы сделать это с помощью FormArray. Был бы такой подход правильным?

coder 17.05.2024 16:53

@coder массив формы, мы можем передать входной массив, но нам нужно убедиться, что значение раскрывающегося списка выбора правильное, здесь мы используем contact.id в качестве ключа, поэтому нам нужно передать массив чисел, если мы просто используем [value] = "contact" тогда нам не нужно будет преобразовывать массив в массив чисел!

Naren Murali 17.05.2024 17:07

Другие вопросы по теме