Javascript 角度对话框更改总是覆盖UI

Javascript 角度对话框更改总是覆盖UI,javascript,angular,typescript,Javascript,Angular,Typescript,我在一个角度对话框中传递数据,但与此同时,当我在对话框中编辑某些内容时,它会覆盖数据,即使我没有保存它们。 例如,我有一个对象并单击“编辑”。 它将打开一个包含此对象所有数据的角度对话框 是否只能在单击“保存”按钮时更改数据。 我听说了Object.assign,它可能很有用,但不知道如何使用它。 我尝试了对象。分配,但无效。 为什么不起作用?我认为this.data包含另一个数据,即this.data.education。 请参见下面的代码 这是我的对话框代码 constructor(@Inj

我在一个角度对话框中传递数据,但与此同时,当我在对话框中编辑某些内容时,它会覆盖数据,即使我没有保存它们。 例如,我有一个对象并单击“编辑”。 它将打开一个包含此对象所有数据的角度对话框

是否只能在单击“保存”按钮时更改数据。 我听说了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 Education {
  subCategories: EducationSubCategory[];
}


 export interface EducationSubCategory {
  name: string;
  startDate: number;
  endDate: number;
  graduation: string;
  title?: string;
  description: string;
}

最好在将对象发送到对话框之前复制该对象。这样您的原始数据就不会被编辑:

   const dialogRef = this.dialog.open(DataDialogComponent, {
     data: _.cloneDeep(data),
   });
对于深度克隆,我建议您使用库。它有一个名为“cloneDeep”的函数,用于复制包含所有嵌套对象的对象

DataDialogComponent.ts
中,保存编辑时,可以通过DialogRef将更新的数据发送回父组件:

  save(): void {
    this.dialogRef.close(this.data)
  }
在父组件中,您可以订阅DialogRef并更新原始数据:

   dialogRef.afterClosed().subscribe((updatedData) => {
     if (updatedData) {
       this.data = updatedData;
     }
   });
完整代码
ParentComponent.ts

import { 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;
      }
    });
  }
}
import { 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()
  }
}
DataDialogComponent.ts

import { 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;
      }
    });
  }
}
import { 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()
  }
}
从'@angular/material/DIALOG'导入{MatDialogRef,MAT_DIALOG_DATA};
导出类DataDialogComponent实现OnInit{
建造师(
@注入(MAT_DIALOG_DATA)公共数据:EditEducation,
私有dialogRef:MatDialogRef
) {}
//实施你的方法
save():void{
this.dialogRef.close(this.data)
}
放弃():无效{
this.dialogRef.close()
}
}
问题 您正在体验通过引用传递变量的情况

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 };
    }
  }

是 啊在这里创建副本是个好主意
this.data=Object.assign({},data)
this.data={…data}都是可靠的替代方案。如果有嵌套数组或对象,则需要递归复制。如果需要,请确保打开对话框的代码在保存后可以访问更新的值。我已经尝试过,但没有成功。我试过这样的东西<代码>({education:this.data.education}=Object.assign({},this.data))它“不起作用”不是我能帮助的with@AluanHaddad我编辑了我的评论,它再次覆盖了它。我需要在对话框组件或父组件中进行复制吗?您可以在任一位置进行复制。如果在对话框中,则在构造函数中执行,在构造函数中注入值。但我有一个问题,那就是父组件中声明的
education:education
。该接口将子类作为子类别。我将添加它的接口。在editData方法中,我面临一个错误,它是这样说的<代码>TS2559:类型“{education?:EducationSubCategory;edit?:boolean;model?:model;}”与类型“MatDialogConfig”没有共同的属性。