javascript - Angular 对话框的更改总是覆盖 UI
我正在在 Angular 对话框中传递数据,但与此同时,当我在对话框中编辑某些内容时,即使我没有保存,它也会覆盖数据。例如,我有一个对象,我点击编辑它。它会打开一个包含该对象所有数据的 Angular 对话框。
是否有可能仅在我点击保存按钮时更改数据。我听说过 Object.assign,它可能很有用,但不知道如何使用。我尝试过 Object.assign,但它没有起作用。为什么不行,我认为 this.data 保存着与 this.data.education 不同的数据。请看下面的代码,这是我的对话框代码。
constructor(@Inject(MAT_DIALOG_DATA) public data: EditEducation,
private dialogRef: MatDialogRef<EducationDialogComponent>,
public dataService: ModelDataService) { }
ngOnInit(): void {
if (!this.data.edit) {
this.data.education = {} as SubCategory;
} else {
({education: this.data.education} = Object.assign({}, this.data));
}
}
这就是我打开对话框的方式。
<ul>
<li class="fa fa-pencil addIconTop" (click)="editEducation({edit: true, education: subCategory, model: model})"></li>
<button (click)="addEducation({edit: false, model: model})" class="btn"><i class="fa fa-plus addIconBottom"></i></button>
<button [disabled]="education.subCategories.length === 1" (click)="deleteSubCategory(i)" class="btn"><i class="fa fa-trash deleteIconRight"></i></button>
<li class="fa fa-arrow-down moveIconDown"></li>
<li class="fa fa-arrow-up moveIconTop"></li>
</ul>
public editData(data: EditEducation) {
this.dialog.open(DataDialogComponent, {
data,
});
}
public addData(data: EditEducation) {
this.dialog.open(DataDialogComponent, {
data,
});
}
这是一个接口,用来查看是否是一个新对象或是否需要编辑。
export interface EditEducation {
education?: SubCategory;
edit?: boolean;
model?: Model;
}
这是 Education 的接口
export interface Education {
subCategories: EducationSubCategory[];
}
export interface EducationSubCategory {
name: string;
startDate: number;
endDate: number;
graduation: string;
title?: string;
description: string;
}
答案#1
问题
您正在经历一个变量通过引用传递的情况
JavaScript 有 5 种按值传递的原始数据类型:
Boolean、null、undefined、String和Number。
分配非原始值的变量会获得对该值的引用。该引用指向对象在内存中的位置。变量实际上并不包含该值。
当一个引用类型的值(对象)通过=复制到另一个变量时,实际上复制的是该值的地址,就像它是原始类型一样。对象是通过引用复制而不是通过值复制的。
解决方案
解决这个问题最简单的方法是在分配变量时使用展开运算符 (...)。下面是你代码的重构版本,应该可以解决这个问题
constructor(@Inject(MAT_DIALOG_DATA) public data: EditEducation,
private dialogRef: MatDialogRef<EducationDialogComponent>,
public dataService: ModelDataService) { }
ngOnInit(): void {
if (!this.data.edit) {
this.data.education = {} as SubCategory;
} else {
({education: this.data.education} = {...this.data };
}
}
public editData(data: EditEducation) {
this.dialog.open(DataDialogComponent, { ...data});
}
public addData(data: EditEducation) {
this.dialog.open(DataDialogComponent, {...data});
}
答案#2
最好在将对象发送到对话框之前先复制它。这样你的原始数据就不会被修改:
const dialogRef = this.dialog.open(DataDialogComponent, {
data: _.cloneDeep(data),
});
对于深度克隆,我建议你使用 lodash 库。它有一个叫做“cloneDeep”的函数,可以复制对象,包括所有嵌套对象。
在你的 DataDialogComponent.ts 中,当你保存编辑时,可以通过 DialogRef 将更新的数据发送回父组件:
save(): void {
this.dialogRef.close(this.data)
}
在父组件中,您可以订阅 DialogRef 并更新原始数据:
dialogRef.afterClosed().subscribe((updatedData) => {
if (updatedData) {
this.data = updatedData;
}
});
完整代码
ParentComponent.tsimport { MatDialog } from '@angular/material/dialog';
import { DialogComponent } from '../dialog/dialog.component';
import * as _ from 'lodash';
export class SomeComponent implements OnInit {
data: Education;
constructor(public dialog: MatDialog) {}
public editData(data: EditEducation) {
const dialogRef = this.dialog.open(DataDialogComponent, {
data: _.cloneDeep(data),
});
dialogRef.afterClosed().subscribe((updatedData) => {
if (updatedData) {
this.data = updatedData;
}
});
}
}
DataDialogComponent.tsimport { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
export class DataDialogComponent implements OnInit {
constructor(
@Inject(MAT_DIALOG_DATA) public data: EditEducation,
private dialogRef: MatDialogRef<DataDialogComponent>
) {}
// Implement your methods
save(): void {
this.dialogRef.close(this.data)
}
discard(): void {
this.dialogRef.close()
}
}
