The way I thought @Input worked would directly give a big "No!" to this question. However, today I stumbled upon some strange behavior, or maybe I always thought the wrong way about @Input..
I've made a stackblitz to show the issue. This happens in the stackblitz for Angular 7.0.1, but in my local project, it also happens on Angular 6.1.2.
The stackblitz shows a simple parent component that has an object. The object is passed to a child component via @Input. Both the child and parent component have a function that changes the object. They also both show the object's value in the template.
I expected to see that when the parent changes the object, it will change it in the child. However, I did not expect that when the child changes the object, it also changes it for the parent. The stackblitz does show this behavior, however. I always thought you would need to explicitly emit an event via @Output to make a flow to the parent and change it there from the child component.
Two-way data binding refers to sharing data between a component class and its template. If you change data in one place, it will automatically reflate at the other end. For example, if you change the value of the input box, then it will also update the value of the attached property in a component class.
Note: For two way data binding, we have to enable the ngModel directive. It depends upon FormsModule in angular/forms package, so we have to add FormsModule in imports[] array in the AppModule.
The two-way data binding in Angular is used to display information to the end user and allows the end user to make changes to the underlying data using the UI. This makes a two-way connection between the view (the template) and the component class.
AngularJS creates a two way data-binding between the select element and the $ctrl.
The answer is "no". In your example, the value that you pass to the @Input
property is a reference to an object. If you had two-way binding, you could assign a new object to that property in the child component:
this.thing = { name: "world", nbm: 10 };
and the corresponding property in the parent component would be updated accordingly. That is not the case, as you can see in this stackblitz.
However, since the parent and child components have a reference to the same object, they can both modify one of its properties, and that change will be observed in the other component.
In order to implement two-way binding, you can add an @Output
property with the same name followed by Change
, and emit the event when the change occurs:
@Input() thing: any;
@Output() thingChange = new EventEmitter();
setNewObject(){
this.thing = { name: "world", nmb: 10 };
this.thingChange.emit(this.thing);
}
The change will then be reflected to the parent component if the two-way binding syntax is used:
<child2 [(thing)]="thing"></child2>
See this stackblitz for a demo.
If you want to prevent the child component from modifying the original object, you should bind the object properties instead of the object itself:
@Input() thingName: string;
@Input() thingNmb: number;
<child [thingName]="thing.name" [thingNmb]="thing.nmb"></child>
Yes, Angular Change Detection
flows from parent
to child
however what you are experiencing is not related to Object
reference
. Since the shared object in parent
and child
point to the same reference
, it will update in both the component.
Whenever you make any change through child component, shared object will be changed in the parent component as well and Angular will detect changes and trigger the UI update.
However that is not same case with primitive data type. What you have thought is true for primitive data type. In case primitive data type changes moves from Parent to child not vice versa.
Here is the demo for the same - https://stackblitz.com/edit/angular-1wusrc
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With