我认为@Input的工作方式会直接给出一个很大的“否!”这个问题。但是,今天我偶然发现了一些奇怪的行为,或者也许我一直以为@Input错误的方式。
我做了一个stackblitz来说明问题。这发生在Angular 7.0.1的stackblitz中,但是在我的本地项目中,它也发生在Angular 6.1.2中。
stackblitz显示了一个具有对象的简单父组件。该对象通过@Input传递给子组件。子组件和父组件均具有更改对象的功能。它们也都在模板中显示对象的值。
我希望看到当父对象更改对象时,它将在子对象中更改对象。但是,我没想到当孩子更改对象时,它也会为父对象更改它。堆栈闪电确实显示了此行为。我一直以为您将需要通过@Output显式发出一个事件,以建立到父级的流程并在子级组件中进行更改。
答案 0 :(得分:4)
答案是“否”。在您的示例中,传递给@Input
属性的值是对对象的引用。如果您有双向绑定,则可以在子组件中为该属性分配一个新对象:
this.thing = { name: "world", nbm: 10 };
和父组件中的相应属性将相应更新。如您在this stackblitz中所见,情况并非如此。
但是,由于父组件和子组件都引用了同一对象,因此它们都可以修改其对象之一的属性,而该更改将在另一组件中观察到。
为了实现双向绑定,您可以添加一个具有相同名称的@Output
属性,后跟Change
,并在发生更改时发出事件:
@Input() thing: any;
@Output() thingChange = new EventEmitter();
setNewObject(){
this.thing = { name: "world", nmb: 10 };
this.thingChange.emit(this.thing);
}
如果使用双向绑定语法,则更改将反映到父组件:
<child2 [(thing)]="thing"></child2>
有关演示,请参见this stackblitz。
如果要防止子组件修改原始对象,则应绑定对象属性而不是对象本身:
@Input() thingName: string;
@Input() thingNmb: number;
<child [thingName]="thing.name" [thingNmb]="thing.nmb"></child>
答案 1 :(得分:3)
是的,FingerprintManager
从Angular Change Detection
流到parent
,但是您遇到的情况与child
Object
无关。由于reference
和parent
中的共享对象指向相同的child
,因此它将在两个组件中都进行更新。
无论何时通过子组件进行任何更改,共享对象也会在父组件中进行更改,并且Angular将检测到更改并触发UI更新。
但是,与原始数据类型的情况不同。您认为对于原始数据类型是正确的。万一原始数据类型的更改从父级移动到子级,反之亦然。
答案 2 :(得分:1)
将更改检测策略设置为ChangeDetectionStrategy。默认情况下,角度通常会触发更改检测,是的,它将起作用。
将其设置为ChangeDetectionStrategy.OnPush,您将看到不同的行为。
此设置是在组件注释中配置的:
@Component({
selector: 'my-awesome-component',
templateUrl: './my-awesome-component.html',
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyAwesomeComponent{
}
编辑:我只是尝试在您的堆栈闪电中将ChangeDetectionStrategy更改为OnPush,而更改仍在反映。我只是再次阅读了文档,显然总是将其更新的原因是因为按钮上的click事件触发了更改检测,并且更改检测从子级触发到父级。因此,您可以说更改检测像html事件一样冒泡到根。
答案 3 :(得分:1)
双向数据绑定是event
绑定和property
绑定的组合类似于香蕉的语法-其中[(ngModel)]
是{{1}的组合}和[ngModel]
事件
当模型名称后跟(ngModelChange)
单词angular会认识到这将是两种方式的数据绑定并使它像这样工作时,就会出现Change
一词的神奇之处
进入Change
组件Child
是通过@Input()
绑定将数据传递给子对象的一种方式,而property
是从子对象向父对象发送数据的一种方式与@Output()
绑定一样-因此要实现双向绑定,您需要两者都绑定-查看下面的示例
event
在上面的代码中,我们具有getModelList: any[];
@Output() modelListChange: EventEmitter<any[]> = new EventEmitter<any[]>();
@Input()
get modelList(): any[] {
return this.getModelList;
}
set modelList(value) {
this.getModelList = value;
this.modelListChange.emit(this.getModelList);
}
属性和modelList
属性,并具有两个绑定的组合,因此我们可以以modelListChange
的身份访问modelList
属性,这就是您的双向绑定属性
从父级访问-[(modelList)]="value"
现在将基于两种方式的数据绑定来更新父级属性-确保您正确拼写<multi-dropdown [(modelList)]="value"></multi-dropdown>
也是区分大小写的
希望这对您有帮助-谢谢您编码愉快!!