While working in an app, I had to set the value to a variable, (that would get one of three different possible values), depending on which radio button was checked (There were 3 radio buttons the user could select). I was setting this value to certain property of an array of object that was would display only after the user selected a radio button. But the variable never changed in the view. So I simplified the case with a minimalistic example, but I had no luck and I don't know why it does not update the view, even when the variable has been assigned the new value.
Please take a look on this minimalistic example:
This is an app.component.html
<ng-container *ngFor="let item of items">
<p>{{item.name}}</p>
</ng-container>
And this is it's .ts file:
export class AppComponent implements OnInit {
public firstValue: string = "Gatsu";
constructor(private cd: ChangeDetectorRef, private nz: NgZone) {}
ngOnInit() {
this.init();
}
public items = [{ name: this.firstValue }, { name: "Kenshin" }];
init(){
this.firstValue = "Itachi";
// this.cd.detectChanges();
// this.cd.markForCheck()
// this.nz.run(()=>this.firstValue = 'Itachi')
alert(this.firstValue); // ---> this alerts 'Itachi'
}
}
I tried to apply changeDetectorRef
and ngZone
to see if I had luck, but, even having 'Itachi' on the alert
message, the view continued to render the initial value 'Gatsu'.
In the end, I solved it by replacing this.firstValue = "Itachi";
by this.items[0].name = "Itachi"
, but I never knew why the first attempt didn't work.
Can you, good fellows let me understand where is the failure in the first attempt, and what was the best approach to achieve what I was trying to do?
Thanks.
CodePudding user response:
Your solution you found is correct.
This is happening because the underlying type of firstName is a string, which is a value (primitive) type. So when you assign this to the name property of the first point in the array, it copies the value (not the reference). This means further changes to firstName do not affect the array point.
Here is a good article on mdn that goes into detail about these different underlying types: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures
CodePudding user response:
The problem you have is not Angular related since the Framework won't be notified of any change when you set the variable "firstValue" to anything else. That happens because you're not changing the array [0].name value, because when doing so
public items = [{ name: this.firstValue }, { name: "Kenshin" }];
You're not keeping a reference to the variable, you're just setting the key of the object at index 0 to the variable first value which is "Gatsu". In fact, if you put a console.log() here:
init(){
this.firstValue = "Itachi";
console.log(this.items); // <---- console.log here
// this.cd.detectChanges();
// this.cd.markForCheck()
// this.nz.run(()=>this.firstValue = 'Itachi')
alert(this.firstValue); // ---> this alerts 'Itachi'
}
You'll notice that the value of the array is still the same. If you really want to change the key "name" of the object at index 0 you should change the value like so:
this.items[0].name = "Itachi";
Or you could just use the reference:
this.items.find(item => item.name == "Gatsu").name = "Itachi";
I hope this solves your problem.