2

I'm fairly new to Angular, hoping someone can shed some light on this.

Method 1: Say I'm passing a parent object 'x' to a child component using 1 way data binding:

<app-child [x]="x"></app-child>

and my child component modifies it like so in ts:

Input() x;

then later:

this.x.someProperty = 'some new value';

This seems to work fine, my 'x' object in the parent is updated.

However in Angular tutorials & other examples (eg https://stackoverflow.com/a/41465022) it seems the 'proper' way to do this would be Method 2: to use 2 way binding eg:

<app-child [(x)]="x"></app-child>

and in the ts

@Input() x: any;
@Output() xChange = new EventEmitter<any>();

then later:

this.x.someProperty = 'some new value';
this.xChange.emit(x);

I'm currently very happily using Method 1 in Angular 7 without any problems - can anyone explain why (if at all) I should use method 2 instead? It seems more complicated & unnecessary since Method 1 works.

jeremyj11
  • 589
  • 1
  • 5
  • 15
  • You parent property should not be updated. Are you passing an object as `x` and then mutating said object ? – Morphyish Aug 05 '19 at 09:30
  • Are you 100% sure that the value in your parent component is updated? It shouldn't. Unless you're referring to an object attribute, in this case as you have a reference to the object, changing an attribute (`this.x.someAttribute = 'some value'`) will also change it in the parent component. – julianobrasil Aug 05 '19 at 09:31
  • yes you're both correct - x is actually an object - I simplified it to a string for the sake of the question.. – jeremyj11 Aug 05 '19 at 09:32
  • have editted the question and changed x to an object – jeremyj11 Aug 05 '19 at 09:35

2 Answers2

0

You are using an object, and objects are passed by reference and are mutable.

If you were to use a primitive value like, boolean, which is used in the link you provided, then modifying the variable in the child would not reflect in the parent. You can see it per this demo, where we a using a string, which is also a primitive. For achieving that parent would get the value too, you would need to use Output. Choosing to use two-way-bindning i.e

[(something)]="something" 

or not, is up to you. You could also use one-way-binding the both ways, like:

[something]="something" (somethingHasChanged)="parentFunction($event)" 

So two-way-binding is just a shorthand for the above.

So as mentioned, objects (and arrays) are mutable, so it's important to remember if you some time do not want to reflect changes in parent of what you do in child component.

AT82
  • 71,416
  • 24
  • 140
  • 167
0

Actually this is very good question, I can't find any official explanation too why we shouldn't mutate the @input value, unlike reactJs and vueJs, they officially discourage us to mutate the props.

Other than like what @AJT82 said, primitive value can't be changed via your method 1. This is one of the reason. I guess the another reason is that, mutating @input value in child is bad practice, it make the code more error prone and hard to debug, it also open the chance to allow all the children component to arbitrary update the object which make us hard to trace the changes.

So this is more on good development practice reason, we should use @output to update back our parent object.

Sam YC
  • 10,725
  • 19
  • 102
  • 158