26

When we pass a modelto the child component and it modifies it, the values are just reflected in the child components' local variable and not available to the parent. Can we pass values by reference from parent to child. So the changes are visible there as well.

I have implemented the same using an observable at the service layer. But can't we pass by reference through @Input?

Sumit Agarwal
  • 4,091
  • 8
  • 33
  • 49
  • Can you post a complete example of what you're talking about (maybe with a little more explanation of the expected behavior)? – Paul Samsotha Oct 26 '16 at 10:57
  • I can't post the complete example here. But the exact scenario which I have is that I want to pass the formGroup to my child component and read the values in parent component, which is not happening as only the child formGroup is getting modified. – Sumit Agarwal Oct 26 '16 at 12:05
  • duplicate of http://stackoverflow.com/questions/36246994/how-to-use-two-way-data-binding-between-components-in-angular-2 ? – Supamiu Oct 26 '16 at 12:16

2 Answers2

55

Primitive values (string, num, boolean, object references) are passed by value (copied), objects and arrays are passed by reference (both components get a reference to the same object instance).

Just wrap your primitive values in objects and changes will be reflected on both sides.

Angular2 change detection won't detect changes to values in arrays or object properties (except when binding expressions address them).

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 18
    Note: This is not Angular2- or TypeScript- specific. This is how JavaScript works. – Günter Zöchbauer Oct 26 '16 at 12:21
  • 6
    One of the difficulties of learning Angular is that some critical information such as this tends not to get mentioned in the documentation. There needs to be an effort to collect such information and include it so one does not need to become a JavaScript expert in order to use Angular. – Mickey Segal Jul 12 '17 at 14:28
  • 4
    @MickeySegal That's JavaScript basics and not related to Angular. It doesn't make sense for every web framework to document JS. – Günter Zöchbauer Jul 12 '17 at 14:47
  • 3
    I commend you for your helpfulness of making the point about passing by reference in this thread, but I think that one thing that gives Angular such a steep learning curve is the need to collect all the fine points from JavaScript and TypeScript before being able to write Angular code. At some point in the development of a language it makes sense to cut out the need to learn predecessors such as JavaScript and instead make the Angular + TypeScript documentation and tutorials more self-contained.. – Mickey Segal Jul 13 '17 at 15:06
  • How do I pass objects by value instead of reference? – karthikaruna Feb 22 '18 at 11:36
  • 1
    @karthikaruna you can clone the object before you pass it. A safe way is https://stackoverflow.com/a/42758108/217408, if you don't need deep copy because the objects properties are all primitives, then you can also use one of the other answers to the linked question. – Günter Zöchbauer Feb 22 '18 at 11:47
  • Ya... Doing it with `Object.assign` :) – karthikaruna Feb 22 '18 at 11:52
  • Just a note, if we pass an array as method parameter, assign it as [] inside the method, push a few items in it, these added items will not be reflected in the calling method. Example, this.setArray(arr1); and inside the setArray() method, setArray(arr1) { arr1 = []; arr1.push("one"); arr1.push("two"); } arr1 will remain empty in the calling method. – shanti Apr 03 '18 at 16:46
  • @shanti array is not a primitive, therefore changes will be visible everywhere where a reference to the same array is used. An array is like an object in this regard. – Günter Zöchbauer Apr 03 '18 at 16:51
  • Yup, array is not primitive, still I am getting it as empty in the calling method, when I assign it as [] first inside setArray(arr1), before pushing a few items in it. – shanti Apr 03 '18 at 16:53
  • @shanti I don't know what "assign it as []" means. If you create a copy of the array instead of pasding the reference to the array, the changes tonone array won't effect the copy. – Günter Zöchbauer Apr 03 '18 at 16:55
  • By assign it as [], I mean assigning it the empty array - arr1 = []; So I am assigning it a new array, that means, a new reference, is it? – shanti Apr 03 '18 at 16:58
  • @shanti yes, it looks like you are creating a new array – Günter Zöchbauer Apr 03 '18 at 17:00
  • 1
    ok, got it. That's why it's not reflecting in the calling method. Thanks. – shanti Apr 03 '18 at 17:01
  • @GünterZöchbauer Please can you give me an example how should we bind from parent to child with primitive value (e.g. a boolean). Right now, when I'm changing the boolean flag in the parent, it does not reflect in the child. – ANewGuyInTown Jul 25 '18 at 07:05
3

Actually - there is a "trick" in Angular to allow you to pass a primitive type (like a string or a number) to a child component and have those changes emitted back to the data referenced by the parent component. This is done by creating a "output EventEmitter" whose name exactly matches the input - but suffixed with "Change". I'm not sure if this is documented anywhere in any official Angular documentation - after a cursory check I wasn't able to find this.

Anyway, the best stack overflow post that documents this technique I was able to find was this: https://stackoverflow.com/a/37855138/5692144

There is also this post - but it doesn't specifically discuss the requirement of the naming of the @Output EventEmitter: https://stackoverflow.com/a/43571004/5692144

And I've confirmed this works as described.

I'm not sure why the architects/designers of Angular haven't made this technique a "first class citizen" that doesn't require you to use to obscure/arcane naming convention (for your Output EventEmitter).

Tim
  • 539
  • 2
  • 9