Reputation: 45
I use service socket.io to emit and receive data. When the send button is clicked it emits data and shows "FENEmitInfo" then receives the data and shows "FENSocketioGetCnt" and "FENSocketioFilterCnt".
The console shows data correctly and on time but the textarea does not update all the data on time, there is a delay on showing the data the next time.
How can I fix this?
Thanks in advance.
Data showing when the send button is clicked the first time.
Data showing when the send button is clicked the second time.
Data showing when the send button is clicked the third time.
This is app.component.html
1 <div><textarea id="txtarlogAPI" class="border border-red-500 rounded w-full h-96" [value]="logAPIraw"></textarea></div>
2 <div><button id="btnsendemit01" class="p-1 px-1 border border-red-500 rounded" (click)="sendemit01()">send</button></div>
This is app.component.ts
1 import { Component, OnInit } from '@angular/core';
2 import {FormsModule} from '@angular/forms';
3 import {SvsocketService} from './svsocket.service';
4
5 @Component({
6 selector: 'app-root',
7 standalone: true,
8 imports: [FormsModule],
9 templateUrl: './app.component.html',
10 styleUrl: './app.component.css'
11 })
12
13 export class AppComponent {
14
15 constructor(
16 private socketService: SvsocketService
17 ){}
18
19 SocketioGetCnt: number = 0;
20 SocketioFilterCnt: number = 0;
21 SocketioEmitCnt: number = 0;
22 logAPIraw: string = "";
23
24 ngOnInit() {
25
26 this.socketService.onMsgSocketAPIEmitInfo().subscribe((dt: string) => {
27
28 this.SocketioGetCnt = this.SocketioGetCnt + 1;
29 console.log('FENSocketioGetCnt:'+this.SocketioGetCnt+', dataget:'+dt);
30 this.logAPIraw += 'FENSocketioGetCnt:'+this.SocketioGetCnt+', dataget:'+dt+'\n';
31
32 if((dt.substring(0, 13))=="API_Info_test"){ //(dt=="API_Info_test")
33 this.SocketioFilterCnt = this.SocketioFilterCnt + 1;
34 console.log('FENSocketioFilterCnt:'+this.SocketioFilterCnt+', datafilter:'+dt);
35 this.logAPIraw += 'FENSocketioFilterCnt:'+this.SocketioFilterCnt+', datafilter:'+dt+'\n';
36 }
37
38 });
39 }
40
41 public sendemit01() {
42 this.SocketioEmitCnt = this.SocketioEmitCnt + 1;
43 this.socketService.sendMsgSocketFENEmitInfo("FEN_Info_test_" + this.SocketioEmitCnt.toString());
44 console.log('FENEmitInfo' + " FEN_Info_test_" + this.SocketioEmitCnt.toString() + ' Finished');
45 this.logAPIraw += 'FENEmitInfo' + " FEN_Info_test_" + this.SocketioEmitCnt.toString() + ' Finished'+'\n';
46 }
47
48 }
This is svsocket.service.ts
1 import { ApplicationRef, inject, Injectable } from '@angular/core';
2
3 import { first, Observable } from 'rxjs';
4 import {io, Socket} from 'socket.io-client';
5
6 @Injectable({
7 providedIn: 'root'
8 })
9 export class SvsocketService {
10
11 private socket: Socket;
12
13 constructor() {
14
15 this.socket = io('http://localhost:3000', { autoConnect: false });
16
17 inject(ApplicationRef).isStable.pipe(
18 first((isStable) => isStable))
19 .subscribe(() => { this.socket.connect() });
20
21 }
22
23 sendMsgSocketFENEmitInfo(message: string): void {
24 this.socket.emit('FENEmitInfo', message);
25 }
26
27 onMsgSocketAPIEmitInfo(): Observable<string> {
28 return new Observable((observer) => {
29 this.socket.on('APIEmitInfo', (message: string) => {
30 observer.next(message);
31 });
32 });
33 }
34
35
36 }
Upvotes: 0
Views: 130
Reputation: 1034
It looks like the zone.js
change detection is not catching the change of the value immediately. A blunt workaround would be to to wrap the values update in the NgZone.run()
callback or perhaps wrapping the assignment into setTimeout()
with no interval parameter will be enough to make changes immediately visible.
However I would recommend using an async pipe in the template and not to subscribe to an observable in the component (or at least add takeUntilDestroyed
to the pipe).
Template part:
<div><textarea id="txtarlogAPI" class="border border-red-500 rounded w-full h-96" [value]="logAPIraw$ | async"></textarea></div>
Component part:
logAPIraw$: Observable<string>;
....
this.logAPIraw$ = this.socketService.onMsgSocketAPIEmitInfo().pipe(
scan((currentState, dt: string) => {
currentState.log += `FENSocketioGetCnt: ${++currentState.count}, dataget: ${dt}\n`;
return currentState;
}, {count: 0, log: ''}),
map(({log}) => log),
);
Here is a working StackBlitz example: https://stackblitz.com/edit/stackblitz-starters-9bsnfu?file=src%2Fmain.ts
Upvotes: 0
Reputation: 8623
Beside using async pipe, you could also use checkDetector markForChange
export class AppComponent {
logAPIraw: string;
constructor(private cdr: ChangeDetectorRef) {}
sendemit01() {
// Your logic that updates the model
this.logAPIraw = 'newValue';
// Mark for check
this.cdr.markForCheck();
}
}
Upvotes: 0