Updating parent object data in child: A step-by-step guide

Currently, I am in the process of creating a custom dropdown component. Within this component, I have a config object that is initialized within the ngOnInit() method. This config object combines both default configurations as well as user-provided configurations through an @Input(). However, upon making changes to the config object from the parent component at runtime, I noticed that these updates are not reflected in the ngOnChanges() method of my child component.

In an attempt to resolve this issue, I have made adjustments:

Child Component

@Input() config: MyConfig;
        @Input() disabled: boolean
        
        ngOnChanges() {
                console.log('config', this.config); // this is not updating
                console.log('disabled', this.disabled); // this is being detected
            }

Parent Component HTML

<button (click)="changeConfig()">Change Config</button>
<app-child [config]="customConfig" [disabled]="newDisabled"></app-child>

Parent Component TypeScript

newDisabled = false;
customConfig = {
        value: 'code',
        label: 'name',
        floatLabel: 'Select'
    };

changeConfig() {
    this.customConfig.value = 'name';
    this.newDisabled = true;
}

The state change works for the disabled variable, however, it does not apply to the config. Is there something I am missing or doing incorrectly? Any assistance would be greatly appreciated.

Answer №1

Your issue stems from the fact that your ngOnInit is assigning a new object to the config variable. This disrupts the reference to the original object due to @Input() being called only once, resulting in changes not being detected.

To resolve this, you can utilize a setter and getter. Below is a StackBlitz demo showcasing how to address this:

Link to StackBlitz Demo

Parent Component:

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

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  newDisabled = false;
  customConfig = {
    value: 'code',
    label: 'name',
    floatLabel: 'Select',
  };

  changeConfig1() {
    this.customConfig.value = 'name1';
    this.newDisabled = true;
    console.log('Change Config 1');
  }

  changeConfig2() {
    this.customConfig.value = 'name2';
    this.newDisabled = true;
    console.log('Change Config 2');
  }
}

Child Component:

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

class MyConfig {}

@Component({
  selector: 'hello',
  template: `<h1> config: {{config | json}}</h1><h1> disabled: {{disabled}}</h1>`,
  styles: [],
})
export class HelloComponent {
  private _defaultConfig = {
    key: 'default',
  };

  @Input() disabled: boolean;

  private _config: MyConfig;
  @Input() config: MyConfig;
  set () {
    if (!this.config) {
      this.config = new MyConfig(); // it is a class
    } else {
      this._config = {
        ...this.config,
        ...this._defaultConfig,
      };
    }
  }
  get () {
    return this._config;
  }

  ngOnChanges() {
    console.log('config', this.config);
    console.log('config', this._config);
    console.log('disabled', this.disabled);
  }
}

Answer №2

The issue lies in the fact that the change detection mechanism is only triggered when there is a modification to the object customConfig. In your scenario, only the value property receives an update. To address this, you can make the following adjustment in the parent.component.ts:

changeConfig() {
    this.customConfig = Object.assign(this.customConfig, { value: 'name'});
    this.newDisabled = true;
}

By implementing this solution, a fresh configuration object will be generated with the updated value property along with all the other existing attributes of the original customConfig.

Answer №3

When comparing input objects, they are done by reference. To ensure changes in your child component and to trigger ngOnChanges, follow these steps:

changeConfig() {
 this.customConfig = {...this.customConfig, value: 'name'};;
 this.newDisabled = true;
}

Additionally, move the code below from ngOnInit to ngOnChanges. There is a chance that during initialization, input changes may not yet be available.

if (!this.config) {
   this.config = new MyConfig(); // It is a class
 } else  {
    this.config = {
           ...this._defaultConfig,
           ...this.config
          };
 }

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

The process of transitioning to a different view through a button press

How can I switch to another view by clicking a button in Aurelia? Here is my code: <button class="btn btn-success " click.delegate="save()">New item</button> Typescript configureRouter(config: RouterConfiguration, router: ...

The script fails to execute on content loaded through AJAX in Django

I have a website with nested div elements that make up a complete set. These elements can be dynamically loaded when the user clicks the "load more" button. The website includes a script that changes the style of the aforementioned div element when the pa ...

What is the correct way to chain Promises for the tasks of creating a new user and hashing their password simultaneously?

My goal is to send a POST request to create a new account. The process involves checking if an account with the same email exists. If not, a new account is created and stored in a user collection. Additionally, password hashing and token generation are per ...

executing jQuery toggle on freshly generated content

I have a webpage that I designed using jQuery. Within this page, there is a table with rows assigned specific color classnames (e.g., tr class="yellowclass"). Users can filter the rows by clicking checkboxes to show/hide tables of different colors. The i ...

Using jqgrid to customize column header tooltips which are distinct from the actual column label

From what I gather, there are multiple methods for setting distinct column header tooltips. At the moment, my approach involves using jQuery's .attr() to set the tooltips. I'm curious if there is a more streamlined way to save the custom header ...

Create a new ASP.NET MVC project and integrate Angular 2 for a dynamic web application

I'm currently delving into the world of Angular 2 with Typescript. The primary resource I am using is QuickStart with Angular 2. From this and other examples, it has been emphasized to create a package.json file that outlines all dependencies for th ...

Encountering an "AJAX not a function" error while using the d3/flask interface

Hey there! I'm new to the world of JavaScript and AJAX. Take a look at this d3 function I've been working on: var node = g.selectAll(".node") .data(root.descendants()) .enter().append("g") .attr("class", function(d) { return "node" + ...

What is the best way to present these values with spaces in between each word?

When I use console.log(JSON.stringify(selected["1"]?.others)), the output is: ["Cars","Books","Necklaces"] On the screen, however, when displaying this data, all the words appear together without spaces. It looks li ...

What's the best way to position an ion-label at the top of the stack

I'm having trouble creating an input label similar to the new Google style. However, when the label moves up, it gets cut in the middle as shown here. Despite trying to adjust the margin, padding, and Z-index, none of these solutions have resolved my ...

How to structure nested objects within a JavaScript object?

I am looking to create a hierarchical object structure similar to the following: record 1 {id, name, desc} record 2 {id, name, desc} record 3 {id, name, desc} record 4 {id, name, desc} This is a nested structure whe ...

Translating PCRE(PHP) regular expressions into ECMAScript(Javascript) syntax

I have this PCRE Regex that I'm using to validate JSON strings, but now I need to convert it to JavaScript so I can use it for validation in a React application. PCRE Regex - /(?(DEFINE) (?<json>(?>\s*(?&object)\s*|\s* ...

Issues encountered while building an Asp.net core 2/Angular 4 template

I've used the Asp.net core 2/Angular 4 template with the .Net core 2 SDK to create a project. When I use dotnet build or dotnet run, it doesn't generate a new dist folder for the client-side Angular project. My editor of choice is Visual Studio ...

Experimenting with JavaScript within an Immediately Invoked Function Expression

My team leader is requesting that I encapsulate my JavaScript code within an Immediately-Invoked Function Expression (IIFE). However, I am struggling to use spyOn in my Jasmine spec file. How can I properly use spyOn on the following: (function(){ fu ...

Guide to activating a reaction following an occurrence in a React component

I have started developing a React application that loads blog posts along with their associated comments. The challenge I am facing is how to trigger a refresh of the comments component and display the new comment immediately after it has been submitted. ...

Exploring the world of two-dimensional arrays in D3 programming

I am interested in visualizing data obtained from the census data API, specifically from the ACS survey. The data is not in a typical JSON format, but rather as a two-dimensional array. It appears like this: [ [ “POPULATION”, “DATE”, ...

The new and improved Vue 3 computed feature in the Composition API

The temporary object appears as: tmp : { k1: { k2 : { k3 : [abc, def] } } To access k3 in the setup, it should be: tmp.value.k1.k2.k3[0 or 1]. I am looking to change its name to something like - k3_arr = tmp.value.k1.k2.k3; Within my Vue single componen ...

Updating styled-components variables based on media queries - A step-by-step guide

My current theme setup looks like this: const theme = {color: red}; Within my components, I am utilizing this variable as follows: const Button = styled.button` color: ${props => props.theme.color}; `; I am now faced with the challenge of changin ...

Adding a fresh element to an object array in TypeScript

How can we add a specific value to an array of objects using TypeScript? I am looking to insert the value 1993 into each "annualRentCurrent" property in the sample object. Any suggestions on how to achieve this in TypeScript or Angular? Thank you! #Data ...

Using an array and a variable for a JavaScript assignment

Let's say we have an array in Javascript like this: var arr = ['item1', 'item2', 'item3']; I need to concatenate all the values in the array into a single variable. The resulting variable should look like this: var it ...

Navigating a JSON object using jQuery

My current project involves sending a Json response to an Ajax function within my webpage. The structure of the Json response is as follows: {"one": 21, "two": 10, "three": 19, "four": 100} With this setup in place, I am now in the process of developing ...