Is it possible for input properties of array type to change on multiple components in Angular 9?

Encountering an interesting issue that I need clarification on. Recently, I developed a compact Angular application to demonstrate the problem at hand.

The puzzling situation arises when passing an Array (any[] or Object[]) as an @Input property to a child component and modifying a value within the Child. Surprisingly, these alterations are reflected in the Parent as well. As per my understanding from the documentation, this behavior should involve one-way binding requiring an @Output property (EventEmitter) from the child to transmit changes back to the parent.

To illustrate my point, I have included code samples. The provided snippet assigns two properties to the child component - an array of Objects and a plain text string. By utilizing an input field, I attempt to modify the Name1 value along with the plain text content.

This predicament raises the question: Why do adjustments made to the data array reflect in the parent, while modifications to the text string do not show up? Is there any detailed explanation in the documentation or can someone clarify the reason behind this discrepancy?

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

https://i.sstatic.net/IukJr.png

Image Displaying Data With the Changes

https://i.sstatic.net/jdfsX.png

Answer №1

When dealing with javaScript / typeScript, it's important to note that objects and arrays are passed by reference, not by value like in Angular

If you make changes to an array in one place, those changes will be reflected in other places as well

To prevent this, you can pass a copy of the array instead of the original array itself

An effective way to create a copy of an object or array is by using the following method:

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

This can be implemented in the app component template as shown below:

<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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Can the contents of a JSON file be uploaded using a file upload feature in Angular 6 and read without the need to communicate with an API?

Looking to upload a JSON file via file upload in Angular (using version 6) and read its contents directly within the app, without sending it to an API first. Have been searching for ways to achieve this without success, as most results are geared towards ...

Can you conduct testing on Jest tests?

I am in the process of developing a tool that will evaluate various exercises, one of which involves unit-testing. In order to assess the quality of tests created by students, I need to ensure that they are effective. For example, if a student provides the ...

Enforcing TypeScript restrictions on method chaining during object creation

Let's consider this unique sample class: class Unique { public one(): Pick<this, "two" | "three"> { return this; } public two(): Pick<this, "three"> { return this; } public three(): string { ...

Issue with Ionic Native File: File.writeFile function - file is not being created and there is no callback response

I've exhausted all the different solutions I could find, but unfortunately, the file isn't getting saved and nothing seems to be happening. The callback functions aren't being called - neither success nor error. Here are the solutions I&apo ...

Set the variable value by clicking on another component within *ngFor in Angular 2

I am attempting to use *ngFor to pass an object to another component, but only the last object in the table is being passed. The object that was clicked should be displayed instead. How can I solve this issue? <tr data-toggle="control-sidebar" *ngFor=" ...

Issue with running Angular Application through docker-compose.yml file is stopping the execution

Below is the docker file I have created for my angular application: Dockerfile: # base image FROM node:10.16.0-alpine AS build-step # set working directory WORKDIR /app COPY package.json ./ RUN npm install COPY . . RUN npm run build FROM nginx:1.16.1-alp ...

Steer clear of creating new instances within loops in Angular

I am facing an issue with a bug in my code related to the green software scanning of casts. public addFilesToQueue(files: FileList | any): void { const addedFiles: AttachmentItem[] = []; for (let iFileId = 0; iFileId < files.length; ...

Having trouble with the ag-grid demo - grid not displaying as intended

Struggling to wrap my head around the "ag-grid" Typescript grid component for use in my Angular 6 applications. The website seems promising, but I am having trouble getting their "Getting Started" demo to function on my setup. I followed all the setup st ...

I'm having trouble linking MikroORM migration to Postgresql - the npx command keeps failing. Can anyone offer some guidance on what

I am encountering a situation similar to the one described in this post. I'm following Ben Awad's YouTube tutorial: you can see where I am in the tutorial here. Objective: My goal is to execute npx mikro-orm migration:create in order to generate ...

What are the Typescript object types where the keys are functions that take a single generic argument consistently?

Explaining this concept in English is quite challenging, but here's what I'm aiming for: const operations = { store: (input: T): T => { return input; }, discard: (input: T): void => { console.log(input); } } In both fun ...

Angular 2 Component attribute masking

In my Angular 2 component called Foobar, I have defined a property named foobar: import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-foobar', templateUrl: './foobar.component ...

React with Typescript: It appears that you are attempting to utilize Typescript without having it properly installed on your system

I am embarking on creating a React application integrated with TypeScript. Initially, I visited the React website to seek guidance on incorporating TypeScript in my project. The website directed me to execute the following command in the terminal: npx crea ...

Adding an element within an ngFor iteration loop

I'm currently working on a code snippet that displays items in a list format: <ul> <li *ngFor="#item of items">{{item}}</li> </ul> These items are fetched from an API through an HTTP call. Here's the code snippet for tha ...

Filtering an array of objects in TypeScript based on the existence of a specific property

I'm attempting to filter objects based on whether or not they have a specific property. For example: objectArray = [{a: "", b: ""}, {a: ""}] objectArray.filter( obj => "b" in obj ).forEach(obj => console. ...

Utilizing ngModel with a Pipe

When attempting to apply a date pipe on an Input element, the following code was initially used: <div class="section"> <h6 style="font-weight:bold">From Date</h6> <input [(ngModel)]="Schedule.FromDate | date:'fullDate' ...

The ngAfterContentInit lifecycle hook is not triggered when the parent component updates the child component

I am trying to understand the functionality of the ngOnChanges callback in Angular. I have implemented it to observe changes in a property annotated with the Input decorator as shown below: @Input() postsToAddToList: Post[] = []; However, after compiling ...

What is the most effective method for obtaining the ViewContainerRef of a mat-row in Angular 4

I am currently working with a mat-table and I'm looking to retrieve the ViewContainerRef of a clicked row in order to add another component within that specific row. Can anyone suggest the most effective method to obtain the ViewContainerRef of a row? ...

The React Functional Component undergoes exponential re-renders when there is a change in the array

I'm encountering a problem with one of my functional components. Essentially, it maintains an array of messages in the state; when a new message is received from the server, the state should update by adding that new message to the array. The issue ar ...

Guide to integrating validators into a formModel with Angular's reactive forms

Currently, I am in the process of learning about reactive forms in Angular and have a question regarding how to set a property as required or any other validator when using class model for defining form groups. You can find more information on reactive fo ...

Triggering an event from a component to its parent module resulting in an exception situation

Here is my app.component.ts code: import { Component, Input, OnInit, OnChanges, SimpleChanges} from '@angular/core'; import {Counter } from './counter' @Component({ selector: 'my-app', template: ` <custom-counter [ ...