【问题标题】:How to pass object by value into Angular2+ component如何按值将对象传递给Angular2 +组件
【发布时间】:2018-07-11 22:50:12
【问题描述】:

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

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

  constructor() {
  }

  ngOnInit() {
  }
}

我将 ChildComponent 嵌套在 ParentComponent 中。

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

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

如何防止这种情况发生?有没有办法通过价值传递?有什么最佳做法吗?

【问题讨论】:

  • 不能传值,但是可以在ngInit中对foo对象做deepcopy,然后将新对象引入到html中...about the deep copy
  • 我知道如何在 javascript 中对对象进行深度复制,而且我也知道对象是通过 javascript 中的引用传递的,这与角度无关。但是,我认为可能有一种角度特定的方式来处理这个问题,因为我确信我不是第一个遇到这个问题的人。
  • 您好 - 如果答案回答了您的问题,请考虑将其标记为已接受;如果您认为它有帮助,请考虑将其标记为已接受,以便其他人知道您的问题已得到解答/答案是否对您有用。如果您不觉得我的回答回答了您的问题/没有帮助,请不要担心,只是想让您了解该功能。欢迎来到 SO :)

标签: javascript angular typescript parameter-passing pass-by-value


【解决方案1】:

好的,到目前为止我最好的解决方案如下所示:

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"。我在这里错过了什么吗?有什么理由不做我想做的事吗?

【讨论】:

    【解决方案2】:

    正如 Gunter 在此答案中所说:Angular2: Pass by reference to interact between components

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

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

    事实上,我想说的是,如果您将一个对象传递给子组件并尝试在其中更改它,那么您就是在更新同一个对象,因此从某种意义上说,值保持不变是一种“不错”同步。

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

    【讨论】:

    • 谢谢。让我感到困惑的是,这正是 2-way-binding 的用途,对吧?因此,单向绑定的行为不应与 imo 相同。我目前正在做的是使用setter()getter()@Input,我只是克隆传入的对象。我想为此创建一个装饰器,所以我不必到处重复它,但我不知道如何做类似于@Input 装饰器的事情。
    • 不客气 :) 对于 getter / setter 甚至自定义装饰器,这是一个有趣的想法。不幸的是,这只是使用 Javascript (Typescript) 的一部分:/
    【解决方案3】:

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

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

    【讨论】:

    • 没有任何解释的代码转储很少有帮助。 Stack Overflow 是关于学习的,而不是提供 sn-ps 来盲目复制和粘贴。请编辑您的问题并解释它如何比 OP 提供的更好。
    【解决方案4】:

    你可以试试 常量复制 = { ...原始 } 创建对象的副本

    【讨论】:

      猜你喜欢
      • 2018-07-15
      • 2016-05-10
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 2016-07-13
      相关资源
      最近更新 更多