Reputation: 4910
I am having some unexpected "behavior" for my BehaviorSubject in Angular. When my app loads, I get a bunch of objects (statuses) and set them to an observable:
public statuses$ = new BehaviorSubject<any>(null)
public getStatuses(): Promise<any> {
return this.http.get<any>(this.url, { headers: this.headers })
.toPromise()
.then(res => {
this.statuses$.next(res);
return res;
});
}
In my component, I subscribe during ngOnInit and assign it to a variable so I can use it in my template:
ngOnInit() {
this.appointmentStatusesService.statuses$.subscribe(statuses => {
this.statuses = statuses;
});
}
Simple enough. Short version of what I am doing: I loop through those statuses in my HTML Template w/ngFor. The user clicks on the status, and it displays the status via a form. (this is the function that is used when a user clicks on a status):
public viewStatus(seqNo: number) {
const statuses = this.appointmentStatusesService.statuses$.getValue();
for (let x = 0; x < statuses.length; x++) {
if (statuses[x].seqno === seqNo) {
this.currentStatus = statuses[x];
break;
}
}
}
Now, the issue I am running into is that any changes that are made to the form, also change the statuses$ observable, even though I am not calling .next(). This is what my form looks like:
<input type="text" class="form-control" [(ngModel)]="currentStatus.name">
Somehow, when the name of currentStatus is changed (which was assigned when the user clicked "VIEW STATUS", it ALSO changes the statuses$ observable. In other words, whatever changes are made to currentStatus object are also done on to statuses$ observable. It's as if there is a two way binding of some sort. I was under the impression that, in order to push changes to an BehaviorSubject, you had to call .next() method. I perhaps am misunderstanding how BehaviorSubject works but I would really appreciate it if someone were able to tell me where I went wrong :\ thank you!
Upvotes: 2
Views: 1082
Reputation: 934
I think the problem is here:
this.currentStatus = statuses[x];
So you are only copying the reference of the status and therefore if you edit currentStatus, you are also editing the status in your list. First thing you could try, is to create a new object like that
this.currentStatus = { ...statuses[x] };
My general suggestion would be to rewrite it a little to avoid subscriptions and too much local state. I've done it with dummy data and it works fine and is very easy:
// template
<p *ngFor="let s of statusses$ | async" (click)="statusClicked(s)">{{ s }}</p>
<input type="text" class="form-control" [(ngModel)]="currentStatus">
// script
statusses$ = new BehaviorSubject(['status1', 'status2', 'status3']);
currentStatus: string;
statusClicked = (s: string) => this.currentStatus = s;
Upvotes: 1