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