Reputation: 43
When I run this program, initially I get the output as false
, 5
, 500
as I have initialized them in the child component like that, but when I try to click on update button, I am not able to revert to the previous values. I am expecting the output to be true
, 10
, 1000
, but I am getting it as false
, 5
, 1000
. Only the number which was different got changed.
How can I solve this issue so that I can get the values whatever I set in the parent component?
Link to stackblitz.
app-component.html
<span (click)="clickme()">Update data</span>
app-component.ts
export class AppComponent {
public parentBool: boolean;
public parentNum: number;
public p2: number;
public ngOnInit(): void {
this.parentBool = true;
this.parentNum = 10;
this.p2 = 100;
}
public clickme(): void {
this.parentBool = true;
this.parentNum = 10;
this.p2 = 1000;
}
}
hello.component.ts
@Component({
selector: 'hello-comp',
template: `
<div>
Boolean value is - {{boolChild}} <br/>
Number value is - {{numChild}} <br />
Second number is - {{numChild2}}
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent {
@Input() boolChild: boolean;
@Input() numChild: number;
@Input() numChild2: number;
public ngOnInit(): void {
this.boolChild = false;
this.numChild = 5;
this.numChild2 = 500;
}
constructor(private _cd: ChangeDetectorRef){}
public ngOnChanges(changes: {}): void {
// this._cd.detectChanges();
console.log(changes);
}
}
Upvotes: 4
Views: 6527
Reputation: 1487
Well your problem is when everything is initialized
Parent value is True and Child Value is False
You are clicking on parent span. This sets the parentBool value to True. This is not a change when it comes to Parent Component. Hence the Change detection does not fire.
I forked this https://stackblitz.com/edit/angular-rgdgd6 from your link below https://stackblitz.com/edit/angular-jv3sjz
You can try 2 different approachs
Upvotes: 0
Reputation: 31125
This is how the input variables in the child component is initialized at the moment.
AppComponent
, trigger ngOnInit
and render the template.MyComponent
, trigger ngOnChanges
. This will show in the console log as follows{
"boolChild": {
"currentValue": true,
"firstChange": true
},
"numChild": {
"currentValue": 10,
"firstChange": true
},
"numChild2": {
"currentValue": 100,
"firstChange": true
}
}
Trigger ngOnInit
(note: this is triggered after ngOnChanges
) in MyComponent
assign values false
, 5
and 500
. This is the reason why these values are shown in the template and not the one sent initially from the AppComponent
.
Click Update data
button in the AppComponent
which will push values true
, 10
and 1000
. It will show the following output
{
"numChild2": {
"previousValue": 100,
"currentValue": 1000,
"firstChange": false
}
}
According to ngOnChanges
in the MyComponent
, the previous values were true
, 10
and 100
(from the ngOnInit
of the AppComponent
). The values false
, 5
and 500
were not registered by the ngOnChanges
because they weren't changes through the Input()
. And so changes
shows the only object that has been changed from it's previous state, which is numChild2
. The other 2 values stay the same and they aren't reflected in the ngOnChanges
.
One solution would be to avoid assigning values in the ngOnInit()
hook in the child and assigning the values during definition.
_boolChild: boolean = false;
_numChild: number = 5;
_numChild2: number = 500;
Even with these changes, you will still observe only numChild2
object in the changes
variable when you click the button because that is how SimpleChanges
works. It will only show the value that has been changed from it's previous state, it won't reflect the values that stay the same.
Here is the hook calling order for reference
Upvotes: 0
Reputation: 565
have you tried calling detectChanges before anything else?
ngOnInit() {
this._cd.detectChanges();
....rest of your code...
}
Btw, I don't understand why you are setting the same values in the ngOnInit() as on line 14 & 15. Actually you don't need to...
Upvotes: 0
Reputation: 29335
Input bindings occur right before ngOnInit, you’re overriding the values in ngOnInit.
Put your defaults in the declaration:
@Input() numChild: number = 5;
Like that
Upvotes: 2