Tips on how child component can detect when the object passed from parent component has been updated in Angular

In the child component, I am receiving an object from the parent component that looks like this:

{
  attribute: 'aaaa',
  attribute2: [
    {
      value
    },
    {
      value
    },
    {
      value
    },
  ]
}

This object is passed to the child component as an @Input. When changes are made to the objects inside the attribute2 array, I want the child component to detect these changes and update accordingly. Since manipulating the object directly did not work, I ended up cloning the entire object in the parent component using (

this.object = _.cloneDeep(this.object)
) so that the child component can recognize the changes.

Is there a more efficient way to achieve this without having to clone the entire object? Thank you for your help!

EDIT:

Child Component

export class ChildComponent implements OnInit, OnChanges {
  @Input() public object: any;
}

html

<div>
   <span>{{object.attribute}}</span>
   <div *ngFor="let items of object.attribute2">{{item.value}}</div>
</div>

Parent Component

export class ParentComponent implements OnInit {
  public object: any;

  updateObject() {
      this.object.attribute2[1] = 'Changed value';
      this.object = _.cloneDeep(this.object);
  }
}

html

<div>
   <child-component [object]="object"></child-component>
</div>

Answer №1

Utilizing EventEmitter and service communication proves to be an effective method for triggering changes in the child component.

@Tony suggests using ngOnChanges() as a quick way to detect changes in bounded properties. However, relying on this hook can have long-term consequences as it will run every time any bound property changes, whether intentionally or not.

To demonstrate service-based communication, I have provided an example:

In this scenario, I bind an Array to the child component using @Input(), where new data additions update the array in the parent component. Subsequently, the latest value is passed through the service, which emits this value. The child component then subscribes to this value to execute relevant code.

The Service:

import { Injectable, EventEmitter } from '@angular/core';

@Injectable({
    providedIn: "root"
})
export class DataService {

  dataUpdated:EventEmitter<any> = new EventEmitter();

  constructor() { }

  setLatestData(data) {
    this.dataUpdated.emit(data);
  }

}

Child Component TS

import { Component, OnInit, Input } from '@angular/core';
import { DataService } from '../data-service.service';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {

  @Input() allData: [];
  latestData: any;

  constructor(private dataService: DataService) { }

  ngOnInit() {
    this.dataService.dataUpdated.subscribe((data) => {
      this.latestData = data;
    });
  }

}

Child Component HTML

<p>
Latest Data: {{ latestData }}
</p>
<h3>List:</h3>
<li *ngFor="let data of allData">
  {{ data }}
</li>

Parent Component TS

import { Component } from '@angular/core';
import { DataService } from './data-service.service'

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular';
  dataArr = [];

  constructor(private dataService: DataService){}

  onAddTimestamp() {
    let timestamp = new Date();
    this.dataArr.push(timestamp);
    this.dataService.setLatestData(timestamp);
  }

}

Parent Component HTML

<hello name="{{ name }}"></hello>
<p>
  Start editing to see some magic happen :)
</p>
<button
(click)="onAddTimestamp()"
>
  Add Timestamp
</button>
<app-child
[allData] = "dataArr"
></app-child>

Answer №2

Implementing the ngOnChanges() method within your component is crucial.

The ngOnChanges function is executed immediately after checking the data-bound properties, but before inspecting the view and content children if any changes are detected.

An example implementation could look like this:

@Input() item: string;

ngOnChanges(changes: SimpleChanges) {
    console.log(changes.item.currentValue);
    // You can access item.previousValue as well as
    // item.firstChange to compare old and new values
}

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

Angular - Detecting Scroll Events on Page Scrolling Only

I am currently working on implementing a "show more" feature and need to monitor the scroll event for this purpose. The code I am using is: window.addEventListener('scroll', this.scroll, true); Here is the scroll function: scroll = (event: any) ...

What is the best way to pass an email as a Laravel parameter within a function using Angular?

I'm currently working on a feature that allows users to delete their account only if the input field matches their email address. However, I encountered an error: Error: $parse:lexerr Lexer Error when attempting to set this up. Here is my HTML code: ...

Skip a single test from a suite in Firefox using Protractor automation framework

I have a collection of tests in my tests folder, all named with the convention ending in spec.js. By using the */spec.js option in the Config file, I am able to run all tests seamlessly. However, I encountered an issue where I needed to skip running a spe ...

Storing values globally in NodeJS from request headers

What is the most effective way to store and access the value from a request header in multiple parts of my application? One approach could be as shown in the following example from app.js: app.get('*', (req, res) => { global.exampleHeader ...

What is the best way to save geolocation coordinates in a Javascript array?

I am attempting to utilize HTML5 geolocation to determine a user's location and then store the latitude and longitude coordinates in an array for future use with Google Maps and SQL statements. However, when I attempt to add these coordinates to the a ...

Saving data in a CSV file on your local device using HTML5

Is it possible to utilize HTML5 for saving or writing data to a local file on the user's file system? I am curious about this functionality, especially since HTML5 now offers the capability to export data from the client and save it as a CSV file. If ...

Send an AJAX request to redirect to a different page on a PHP server

After collecting data from JavaScript, my page transfers it to PHP and then MySQL. The issue arises when I want the page to redirect to different pages based on the database content. I attempted to use the header function, but it only displayed the entire ...

Sending state properties to components within a route

In my React structure, I have the following setup: <Provider store={ store }> <Router> <Switch> <Route path="/how-to" component={ Help } /> <Route path="/start" c ...

Error: The $filter function in AngularJS is not recognized

I have been attempting to inject a filter into my controller and utilize it in the following manner: angular .module('graduateCalculator', []) .filter('slug', function() { return function(input) { ...

Exporting SVG to image in Ionic is successful on Android devices, but the image gets cut off when viewed on

I am facing an issue with exporting an SVG as a base64 encoded image and sending it to the server for storage on Google Cloud Storage. The process works fine on Android and in browsers, but fails when attempted on a physical device running IOS. On IOS, t ...

Only function components can utilize hooks within their body. The useState functionality is currently not functioning as expected

Currently working on a GatsbyJS project and attempting to utilize a Hook, however encountering an error message. Initially, I decided to remove the node_modules folder and package.json.lock file, then executed npm install again, unfortunately without reso ...

Triggering jQuery Submit Form when Form is Modified

I need help with automatically submitting a form using jQuery when an input changes. The specific input I am working with is a date picker, and I want the form to be submitted as soon as a user makes a selection. <form id="select_date" name="select_da ...

Error message: validator is not defined when integrating jquery.validate with jquery.uploadfile package

Currently, I am facing an issue while attempting to incorporate both jquery.validate and jquery.uploadfile on the same page. The error message I'm receiving is: TypeError: validator is undefined if ( validator.settings.rules ) { Interestingly, if ...

What is the best way to send an array of grouped data to a table

Here's how I organized the array: { "2023-10-01": [ { "emp_id": 1, "name": "Aruna", "code": "DO", "date": "2023-10-01" }, { &qu ...

An error has occurred: sendEmail function is not defined

There seems to be a simple issue here that needs my attention before diving into PHP tasks. I plan on using PHPMailer this time around. I've been attempting to learn how to submit a form on localhost for the past week, and now I'm going to try i ...

Draggable HighStock element causing issues with Gridster dragging

I have integrated a stocks chart from HighStocks with gridster, where each gridster block is draggable. However, the stocks time slider gadget can also be dragged and resized. When I move the slider on top of a gridster widget, the entire widget moves alon ...

The deployment of the Fire-base Cloud Function was successful and error-free. However, the function does not appear to exist in the Firebase system

After deploying a JavaScript Cloud Function, it shows that the deployment is completed. However, when I check Firebase, the function is not there. Oddly, TypeScript Cloud Functions deploy successfully. I followed all the steps outlined in the original Fir ...

Enhancing Efficiency and Optimization with jQuery

Recently delving into the world of jQuery, I have been on the lookout for ways to enhance the speed and performance of my code. If anyone has any tips or valuable resources that could aid me in this endeavor, I would greatly appreciate it. Thank you, Bev ...

Invalid Redux store: Element type is not valid; a string type is expected

I am running into an issue while setting up the redux store with typescript for the first time. The error message I am encountering is: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) ...

update the element that acts as the divider in a web address (Angular)

Is it possible to modify the separator character used when obtaining the URL parameters with route.queryParams.subscribe? Currently, Object.keys(params) separates the parameters using "&" as the separator. Is there a way to change this to use a differe ...