Я работаю над системой управления задачами, в которой задачи связаны с контактами и подзадачами. Когда я добавляю или редактирую задачу, система в настоящее время возвращает только идентификаторы контактов и строковые значения подзадач. Однако мне нужно получить полные объекты как для контактов, так и для подзадач.
Как я могу изменить свой код, чтобы получить полные объекты для контактов и подзадач при добавлении или редактировании задачи? Любые рекомендации или примеры будут с благодарностью оценены. Спасибо!
main.ts
@Component({
selector: 'app-root',
standalone: true,
imports: [TaskFormComponent],
template: `
<button (click) = "addTask()">Add Task</button>
<button (click) = "editTask()">Edit Task</button>
`,
})
export class App {
name = 'Angular';
constructor(private dialog: MatDialog) {}
public addTask() {
this.dialog
.open(TaskFormComponent, {})
.afterClosed()
.pipe(filter((task) => task))
.subscribe((task) => {
console.info('Add Task:');
console.info(task);
});
}
public editTask() {
let task: Task = {
id: 1,
title: 'Task 1',
subtasks: [
{
id: 1,
taskId: 1,
description: 'Subtask 1',
isDone: true,
},
{
id: 2,
taskId: 1,
description: 'Subtask 2',
isDone: false,
},
],
contacts: [
{
id: 1,
email: '[email protected]',
name: 'John Doe',
},
{
id: 2,
email: '[email protected]',
name: 'Jane Doe',
},
],
status: TASK_STATUSES['IN_PROGRESS'],
};
this.dialog
.open(TaskFormComponent, {
data: { fromPopup: true, task: task },
})
.afterClosed()
.pipe(filter((task) => task))
.subscribe((task) => {
console.info('Edit Task:');
console.info(task);
});
}
}
задача-form.comComponent.ts
export class TaskFormComponent {
protected readonly Object = Object;
taskForm!: FormGroup;
fromPopup = false;
keywords!: string[];
contacts: Contact[] = [
{
id: 1,
email: '[email protected]',
name: 'John Doe',
},
{
id: 2,
email: '[email protected]',
name: 'Jane Doe',
},
{
id: 3,
email: '[email protected]',
name: 'Max Max',
},
{
id: 4,
email: '[email protected]',
name: 'Anna Anna',
},
];
@ViewChild(ChipFieldComponent) chipFieldComponent!: ChipFieldComponent;
constructor(
private fb: FormBuilder,
@Optional() private dialogRef: MatDialogRef<TaskFormComponent>,
@Optional()
@Inject(MAT_DIALOG_DATA)
public data: { fromPopup: boolean; task: Task }
) {}
ngOnInit() {
this.keywords = [];
this.fromPopup = !!this.data?.fromPopup;
this.taskForm = this.fb.group({
id: this.data?.task?.id,
title: new FormControl(''),
subTasks: new FormControl(''),
contacts: new FormControl(''),
status: TASK_STATUSES['TO_DO'],
});
if (this.data?.task) {
this.taskForm.patchValue({
id: this.data.task?.id,
title: this.data.task.title,
subTasks: this.data.task.subtasks.map((x) => x.description),
contacts: this.data.task.contacts.map((x) => x.id),
status: this.data?.task.status,
});
}
}
public get subTasksFormControl() {
return this.taskForm.get('subTasks') as FormControl;
}
public onSubmit() {
this.dialogRef.close(this.taskForm.getRawValue());
this.onReset();
}
public onReset() {
this.taskForm.reset();
this.chipFieldComponent.keywords = [];
}
}
задача-форма.компонент.html
<div mat-dialog-title>{{ data?.task ? 'Update Task' : 'Create Task' }}</div>
<mat-dialog-content>
<form [formGroup] = "taskForm" (ngSubmit) = "onSubmit()">
<mat-form-field>
<mat-label>Title</mat-label>
<input
matInput
formControlName = "title"
type = "text"
placeholder = "Enter a title"
/>
</mat-form-field>
<app-chip-field
[control] = "subTasksFormControl"
[controlTitle] = "'subtask'"
></app-chip-field>
<mat-form-field>
<mat-label>Contacts</mat-label>
<mat-select formControlName = "contacts" multiple>
@for (contact of 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 (click) = "onSubmit()" 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>
Проблема
Прежде чем приступить к решению, первая проблема заключается в том, что вам нужно установить пустой массив вместо пустой строки в элементе управления subTasks
, чтобы разрешить компонент Mat Chip, который не может добавлять несколько значений.
задача-form.comComponent.ts
this.taskForm = this.fb.group({
...,
subTasks: new FormControl([]),
...
});
Изменения
subTasks
и contact
.задача-form.comComponent.ts
if (this.data?.task) {
this.taskForm.patchValue({
id: this.data.task?.id,
title: this.data.task.title,
subTasks: this.data.task.subtasks,
contacts: this.data.task.contacts,
status: this.data?.task.status,
});
}
<mat-option>
в качестве объекта contact
для элемента управления contacts
.задача-форма.компонент.html
<mat-form-field>
<mat-label>Contacts</mat-label>
<mat-select formControlName = "contacts" multiple [compareWith] = "contactCompareWithFn">
@for (contact of contacts; track contact.id) {
<mat-option [value] = "contact">{{ contact.name }}</mat-option>
}
</mat-select>
</mat-form-field>
задача-form.comComponent.ts
contactCompareWithFn = (contact: Contact, value: Contact) => contact.id == value.id;
data?.task?.id
свойству taskId
Input.задача-форма.компонент.html
<app-chip-field
[control] = "subTasksFormControl"
[controlTitle] = "'subtask'"
[taskId] = "data?.task?.id"
></app-chip-field>
4.1. Добавьте свойство taskId
@Input
, чтобы принять переданное значение.
4.2. Измените keywords
и методы для типа Subtask
.
чип-field.comComponent.ts
export class ChipFieldComponent {
@Input() taskId!: number | undefined;
keywords: Subtask[] = [];
removeKeyword(keyword: Subtask) {
const index = this.keywords.indexOf(keyword);
if (index >= 0) {
this.keywords.splice(index, 1);
this.announcer.announce(`removed ${keyword}`);
}
}
add(event: MatChipInputEvent): void {
const value = (event.value || '').trim();
if (value) {
this.keywords.push({
id: 0,
taskId: this.taskId ?? 0,
isDone: false,
description: value,
} as Subtask);
}
event.chipInput!.clear();
}
}
<mat-chip-row>
, чтобы снабдить value
объектом keyword
и отобразить description
.чип-форма.компонент.html
<mat-chip-row (removed) = "removeKeyword(keyword)" [value] = "keyword">
{{ keyword.description }}
<button matChipRemove aria-label = "'remove ' + keyword.description">
<mat-icon>cancel</mat-icon>
</button>
</mat-chip-row>
Хммм, а ты пробовал без вложенного массива, contacts: []
? Или вы можете поделиться со мной демо-версией StackBlitz для расследования? Спасибо.
Вот демо-версия StackBltz. stackblitz.com/edit/…
Привет, ваш <mat-select>
должен реализовать compareWith
, чтобы он мог отображать предварительно установленное значение на основе id
. Демо
Спасибо. Это мне очень помогло. Есть только одна проблема. когда я нажимаю «Редактировать задачу», контакты, назначенные этой задаче, не отображаются. Я определил контакты: [[]] как пустой массив, но это все равно не работает.