Reputation: 5058
I have a service that handles messages from my server and created an observable for it like so:
serverMessage$: Observable<string>;
private serverMessageSubject: Subject<string>;
constructor() {
this.serverMessageSubject = new Subject<string>();
this.serverMessage$ = this.serverMessageSubject.asObservable();
}
setServermessage(message: string) {
this.serverMessage = message;
this.serverMessageSubject.next(this.serverMessage);
}
I am waiting for this string in my component and adding it to my textarea like so:
.ts file
serverMessage: string;
constructor(
private cs: CommonService
) {
this.cs.serverMessage$.subscribe((message: string) => {
this.serverMessage += message;
});
}
.html file
<div class="col-md-12" *ngIf="serverMessage">
<textarea style="width: 100%" cols="50" rows="10">{{ serverMessage }}</textarea>
</div>
This is where the setServermessage is called:
signalr.service.ts
onMessageReceived(serverMessage: string) {
this.cs.setServermessage(serverMessage);
}
The problem is when I log the messages in my textarea, it outputs the previous message and the current message thus making the outputs duplicated. I just want to append the new messages to the old messsages in my textarea.
Upvotes: 1
Views: 2644
Reputation: 357
Your case is a perfect one for using scan operator
Instead of using a local variable and concatinating strings you can do something like this:
Your service will remain as it is. But you will change your component logic to this
// serverMessage: string; No need anymore
serverMessage$: Observable<string>;
constructor(
private cs: CommonService
) {
this.serverMessage$ = this.cs.serverMessage$
.pipe(scan((accumaltor, message) => accumator + message))
// .subscribe((message: string) => {
// this.serverMessage += message;
// });
// No need to subscribe anymore as we will be using the `async pipe`, but if you need `serverMessage` for something else
// You can remove the comments and make it `=` not `+=` as the messages are already concatinated
}
And then you can do something like this in your template
<!-- notice the async pipe here, remove the need to unsubscribe() at ngDestroy() -->
<div class="col-md-12" *ngIf="serverMessage$ | async as serverMessage">
<textarea style="width: 100%" cols="50" rows="10">{{ serverMessage }}</textarea>
</div>
Upvotes: 3