1

I am running into an issue that I want to ensure is true. I wrote a small Angular application to show what I am talking about.

When I pass an Array(any[] or Object[]) to a child component as an @Input property and change a value in the Child, why are the changes reflected in the Parent? From what I read from the documentation, this is supposed to be a one-way binding, meaning I would have to use an @Output property (EventEmitter) from the child to send the changes back to the parent.

I provided code as an example of what I'm explaining, maybe too extensively. The code has two properties it is sending to the child component, one is an array of Objects and the other is a plain text string. I'm using an input field to change the value of Name1 and the plain text value.

So my question is, why when I make changes to the data array, the changes are reflected in the parent, but when I change the text string, they aren't? Is there somewhere in the documentation that explains this or can somebody explain why this is?

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  arr = [
    {name: 'Name1', data: 'This is data 1..'},
    {name: 'Name2', data: 'This is data 2..'},
    {name: 'Name3', data: 'This is data 3..'},
  ];

  someText = 'This is text';
}

app.component.html

<div style="border: 1px solid grey; padding: 4px;">
  <h4>Parent</h4>
  <ul>
    <li *ngFor="let item of arr">Name: {{ item['name'] }}, Data: {{ item['data'] }}</li>
  </ul>
  <strong>{{ someText }}</strong>
</div>
<child-component [arr]="arr" [someText]="someText"></child-component>

child-component.component.ts

import {Component,  Input} from '@angular/core';

@Component({
  selector: 'child-component',
  templateUrl: './child-component.component.html',
  styleUrls: []
})
export class ChildComponentComponent {

  @Input() arr: any[];
  @Input() someText: string;

  sendChanges(changes: any) {
    this.arr[0]['name'] = changes;
    this.someText = changes;
  }
}

child-component.component.html

<div style="border: 1px solid grey; padding: 4px;">
  <h4>Child</h4>
  <ul>
    <li *ngFor="let item of arr">Name: {{ item['name'] }}, Data: {{ item['data'] }}</li>
  </ul>
  <div><strong>{{ someText }}</strong></div>

  <input type="text" #changes>
  <button (click)="sendChanges(changes.value)">Send Changes</button>
</div>

Image Displaying Data Without Changes

Image Displaying Data Without Changes

Image Displaying Data With the Changes

Image Displaying Data With the Changes

j3ff
  • 5,719
  • 8
  • 38
  • 51
  • array is passed by reference so both of them are pointing to same thing – Barkha Apr 20 '20 at 15:54
  • you can refer to answers here https://stackoverflow.com/questions/35504310/deep-copy-an-array-in-angular-2-typescript – Barkha Apr 20 '20 at 16:01

1 Answers1

1

This is something related to javaScript / typeScript not Angular

Objects and arrays are passed by reference, so if you update the array somewhere, it will be updated in the other place

you can pass a copy of the array rather than passing the array itself

we can use something like this to take a copy from an object or array

let snapshotOfMyArray = JSON.parse(JSON.stringify(myArray));

so we can do that in the app component template

<div style="border: 1px solid grey; padding: 4px;">
  <h4>Parent</h4>
  <ul>
    <li *ngFor="let item of arr">Name: {{ item['name'] }}, Data: {{ item['data'] }}</li>
  </ul>
  <strong>{{ someText }}</strong>
</div>
<child-component [arr]="JSON.parse(JSON.stringify(arr))" [someText]="someText"></child-component>
Mohammed Yousry
  • 2,134
  • 1
  • 5
  • 7