我们假设我有一个接收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
中。
我该怎样防止这种情况?有没有办法通过价值?任何最佳做法?
答案 0 :(得分:2)
好吧,到目前为止我的最佳解决方案是这样的:
@InputByValue
这似乎有效,但是它为单个属性提供了大量代码。我仍然不明白为什么Angular中没有这样的功能(例如[(foo)]="foo"
装饰器)。
我认为当我希望将更改从子节点反映回父节点时,我会使用双向绑定name
。我在这里错过了什么吗?有什么理由不去做我想做的事吗?
答案 1 :(得分:1)
Gunter在这个答案中说:Angular2: Pass by reference to interact between components
原始值(字符串,数字,布尔值,对象引用)按值传递(复制),对象和数组通过引用传递(两个组件都获得对同一对象实例的引用)。
这与Angular无关,它只是Javascript的方式,因而也就是Typescript的工作方式。
事实上,我会说,如果你将一个对象传递给一个子组件并尝试在那里进行更改,那么你需要更新同一个对象,所以它的排序是&# 34,漂亮&#34;以某种方式使价值保持同步。
但是,如果要分叉值,则需要以这种或那种方式创建本地副本。如评论中所述,您可以通过在子组件中执行对象的深层复制然后更改该值来实现。这是一个小Stackblitz示例,说明了这种方法:https://stackblitz.com/edit/angular-axr5zf。
答案 2 :(得分:0)
您可以尝试 const copy = {...原始} 用于创建对象的副本
答案 3 :(得分:0)
您需要生成一个新对象,而不是直接使用输入引用。一种快速的解决方案是使用Spread syntax生成对象的新副本并在模板中使用它。
@Input('foo') fooRef : Foo;
foo: Foo;
.
.
.
ngOnInit() {
// creating a new object using the spread syntax
this.foo = {...this.fooRef};
}