简体   繁体   中英

Angular: I am passing ngmodel in a @input from parent to child; change the value of corresponding @input, the value in parent is updated

Angular: I am passing ngmodel in a @input from parent to child; When i change the value of corresponding @input in child the value in parent is also updated causing it to behave like 2 way binding.Can anyone explain why is it so

parent html:

<app-config-form [data]="param"></app-config> //param is ngModel

child.ts:

@Input() data:any = {}

The behavior you're describing happens when the input isn't a primitive type (number/string/boolean). If it's a complex object (different from null ) and you change any property of the object, that change will reflect on the parent's object, because it's the same: you're dealing with references, not with values.

You must do a deep clone of the input if you want to avoid this situation, like this:

private _data: any;
@Input() set data(d: any) {
  // If you want to improve performance, use this library to do a deep clone:
  // https://github.com/planttheidea/fast-copy
  // otherwise, you can go with JSON.parse(JSON.sringify(...))

  this._data = d ? JSON.parse(JSON.sringify(d)) : null;
}
get data(): any {return this._data;}

Complementary info

Now, as info: to really use the 2-way data binding if you'd like to:

@Input() data:any = {}

// mandatory: the same name of the @Input, suffixed with "Change"
@Ouput() dataChange = new EventEmitter<any>();

Then you can use, in the parent, the "banana-in-the-box" notation:

<app-config-form [(data)]="param"></app-config> //param is ngModel

But the update is not automatically fired. Every time you change it in the child, you must call this.dataChange.emit(value) .

For example (in the child):

buttonClickHandler() {
  this.data = 2;
  this.dataChange.emit(2);
}

You are using [(ngModel)] . It means that you want two way data binding. When you change the value associated with [(ngModel)] , it would react at all where you use it. So use alternate way if you don't have required ngmodel at that variabel.

You need to create a copy of data in your child:

@Input() data:any = {}
childData: any;


OnInit() {
   this.childData = JSON.parse(JSON.stringify(this.data));
}

This will let you modify childData avoiding updates in parent component, because childData is another object than data. In your example, you pass the object from parent into child, but in fact, is the same object and due of this, when you update it in child, this is updated in parent.

Objects are mutable

Mutable is a type of variable that can be changed. In JavaScript, only objects and arrays are mutable, not primitive values.

This is why value changes... There is a good article about immutability in js

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM