如何按值将对象传递到 Angular2+ 组件中

How to pass object by value into Angular2+ component

提问人:Johannes Stricker 提问时间:2/1/2018 更新时间:7/24/2020 访问量:5398

问:

假设我有一个组件,它接受一个实例并显示一个表单来编辑它。Foo

export class ChildComponent implements OnInit {
  @Input() foo : Foo;
  @Output() onChange : EventEmitter<Foo> = new EvenEmitter<Foo>();

  constructor() {
  }

  ngOnInit() {
  }
}

我把它嵌套在一个 .ChildComponentParentComponent

<div id="parent">
  <app-child-component [foo]="parentFoo"></app-child-component>
</div>

现在,即使我在这里使用了单向绑定,因为是一个对象,因此通过引用传递,因此对它所做的任何更改也会反映在 中。fooChildComponentParentComponent

我怎样才能防止这种情况发生?有没有办法通过价值传递?有什么最佳实践吗?

javascript angular typescript 参数传递

评论

1赞 santosh singh 2/1/2018
Angular2 的可能副本:通过引用传递以在组件之间进行交互
1赞 Noki 2/1/2018
你不能按值传递,但你可以在 ngInit 中对 foo 对象进行深度复制,然后将新对象引入 html...关于深拷贝
1赞 Johannes Stricker 2/1/2018
我知道如何在 javascript 中深复制对象,我也了解对象在 javascript 中通过引用传递,这与 angular 无关。但是,我认为可能有一种特定于角度的方法来处理这个问题,因为我确定我不是第一个遇到这个问题的人。
1赞 vince 2/2/2018
你好 -- 如果答案回答了你的问题,请考虑将它标记为已接受,或者如果你认为它有帮助,请点赞,这样其他人就知道你的问题已经得到回答/如果答案对你有用。如果您觉得我的回答没有回答您的问题/有帮助,请不要担心,只是想让您了解该功能。欢迎来到 SO :)

答:

1赞 vince 2/1/2018 #1

正如 Gunter 在以下回答中所说: Angular2:通过引用传递组件之间的交互

基元值(字符串、num、布尔值、对象引用)按值传递(复制),对象和数组按引用传递(两个组件都获得对同一对象实例的引用)。

这与 Angular 无关,这只是 Javascript 以及 Typescript 的工作方式。

事实上,我想说的是,如果你将一个对象传递到一个子组件中,并试图在那里更改它,你就是在更新同一个对象,所以在某种程度上,它有点“好”,使值保持同步。

但是,如果要分叉值,则需要以一种或另一种方式创建本地副本。如注释中所述,您可以通过在子组件中对对象进行深度复制,然后更改该值来做到这一点。下面是一个小的 Stackblitz 示例来说明此方法: https://stackblitz.com/edit/angular-axr5zf

评论

0赞 Johannes Stricker 2/1/2018
谢谢。让我感到困惑的是,这正是 2-Way 绑定的目的,对吧?因此,单向绑定的行为方式不应与 imo 相同。我目前正在做的是使用 a 和 和 ,我只是克隆传入的对象。我想为此创建一个装饰器,这样我就不必到处重复它,但我不知道如何做类似于装饰器的事情。setter()getter()@Input@Input
0赞 vince 2/1/2018
不客气:)对于吸气剂/二传手,甚至是自定义装饰器来说,这是一个有趣的想法。不幸的是,这只是使用 Javascript (Typescript) 的一部分:/
7赞 Johannes Stricker 2/2/2018 #2

好吧,到目前为止,我最好的解决方案是这样的:

export class ChildComponent implements OnInit {
  private _foo : Foo;
  @Input()
  set foo(value : Foo) { this._foo = Object.create(value || null); }
  get foo() : Foo { return this._foo; }

  @Output() onChange : EventEmitter<Foo> = new EventEmitter<Foo>();

  constructor() {
  }

  ngOnInit() {
  }
}

这似乎确实有效,但是单个属性需要大量代码。我仍然不明白为什么 Angular 中没有内置这样的功能(例如装饰器)。@InputByValue

我认为,当我希望更改从子项反射回父项时,我会使用双向绑定。我在这里遗漏了什么吗?有什么理由不去做我想做的事情吗?[(foo)]="foo"

0赞 murilo ramos carraro 7/3/2019 #3

你可以试试 const copy = { ...原文 } 用于创建对象的副本

3赞 wizAmit 5/9/2020 #4

您需要生成一个新对象,而不是直接使用输入引用。一个快速的解决方案是使用 Spread 语法生成对象的新副本,并在模板中使用它。

@Input('foo') fooRef : Foo;
foo: Foo;
.
.
.
ngOnInit() {
    // creating a new object using the spread syntax
    this.foo = {...this.fooRef};
}

评论

3赞 palaѕн 5/9/2020
没有任何解释的代码转储很少有帮助。Stack Overflow 是关于学习的,而不是提供盲目复制和粘贴的片段。请编辑您的问题并解释它如何比 OP 提供的更好。