Home > Net >  How to update object data of parent in child
How to update object data of parent in child

Time:10-30

I am making custom component for dropdown. I have one config object which I am initializing in ngOnInit(), and I am combining the default configs and configs provided by user as an @Input(), But at run time from parent component, If I am making any changes in my config object, it is not updating in ngOnChanges() method of my child.

I tried this:

child component

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

parent component html

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

parent component ts

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

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

for disbale variable it is working, but for config it is not, Am I doing something wrong? please help

CodePudding user response:

You problem is that you ngOnInit is setting the config variable to a new object. Since the @Input() is called once, this breaks your reference to the original object, and changes will not be detected.

You can fix this by using a setter and getter. I have added a stack blitz to demo this bellow.

Blockquote

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);
  }
}

CodePudding user response:

The problem is that the change detection is only triggered if the object customConfig is changed. In you example, only the value property is updated. What you can do is the following in the parent.component.ts:

changeConfig() {
    this.customConfig = Object.assign(this.customConfig, { value: 'name'});
    this.newDisabled = true;
}
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

This will create a new config object which contains the updated value property and all the other old properties of the old customConfig.

CodePudding user response:

Input object are compared by reference, so if you want to reflect changes in your child component and trigger ngOnChanges do this:

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

And also move your below code from ngOnInit to ngOnChanges, chances are that at the time of initialisation input chagnes may not be available.

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