He realizado la implementación de RXJS websocket RXJS Websockets para mi aplicación angular. Se utiliza para mostrar las notificaciones en la página de inicio que es ruta/inicio. Entonces, una vez que el usuario inicia sesión, recibe las notificaciones en una tarjeta de tapete y un conteo en una insignia de tapete usando angular material lib, hasta que todo esté bien. Ahora, si me dirijo a otra página, digamos, por ejemplo, /juegos, todavía recibo mis mensajes WS, lo cual está bien. Pero ahora, si vuelvo a visitar la página de inicio /home, no veo el nuevo mensaje WS que recibí en la ruta /games, muestra el recuento anterior. Este es el problema uno. El segundo problema ahora es que si trato de enviar un nuevo mensaje en vivo a mi aplicación angular, lo escucha correctamente, también actualiza la variable que es la lista de notificaciones en este caso, pero no se sincroniza con la vista HTML. Muestra el recuento que teníamos. cuando iniciamos sesión. A continuación se muestra el fragmento de mi código:
Aquí está la parte HTML que contiene el conteo y la lista de notificaciones:
<button mat-button #menuTrigger="matMenuTrigger" [matMenuTriggerFor]="notifications" <mat-icon [matBadge]="counter" [matBadgeHidden]="counter < 1" matBadgeColor="warn">notifications</mat-icon> </button> <mat-menu #notifications="matMenu"> <ul> <li *ngFor="let item of notificationList; let i = index"> </li> </ul> </mat-menu>Aquí está la parte TS que contiene el código websocket RXJS, un breve fragmento de mi código:
import { webSocket } from 'rxjs/webSocket'; public retryConfig = 3000; public myWebSocket: WebSocketSubject<any>; this.url = 'ws://localhost:8081'; fetchNotificationData() { this.myWebSocket = webSocket(this.url); this.myWebSocket.pipe( retry(this.retryConfig)).subscribe( (dataResponse: any) => { this.counter = this.dataResponse.length; this.notificationList = this.dataResponse; }, // Called whenever there is a message from the server (err: any) => console.error("CONNECTION FAILED::", JSON.stringify(err)), // Called if WebSocket API signals some kind of error () => console.log('complete') // Called when connection is closed (for whatever reason) ); }Cualquier ayuda o consejo será apreciado. Gracias una tonelada.
Saltaré antes de que alguien sugiera usar ngrx u otras cosas de tipo patrón de tienda, aunque eso es más o menos lo que quieres.
Supongo que cada componente está utilizando ese servicio y obteniendo datos de notificación por sí mismos, de forma independiente.
Eso es lo que arregla el patrón de la tienda. La tienda se ocupa de obtener los datos, los componentes solo piden lo que tienen y lo muestran.
Sin embargo, recomiendo encarecidamente no inflar su proyecto con ngrx para hacer esto.
Angular tiene servicios singleton que harán esto con un mínimo de implementación.
Los basicos:
Su servicio de notificación simplemente debe realizar un seguimiento de las notificaciones y, ya sea a través de observables o incluso de accesos simples, permitir que los componentes obtengan la lista. Idealmente observables, supongo, para que puedan suscribirse a las actualizaciones en vivo.
Ya estás haciendo la parte de ahorro, por lo que parece:
(dataResponse: any) => { this.counter = this.dataResponse.length; this.notificationList = this.dataResponse; }, Configure algo que los componentes escuchen y empújelo a través de eso. Si mal no recuerdo, BehaviorSubject almacena lo último que enviaron para que las suscripciones iniciales obtengan algunos datos inmediatos (a diferencia de los observables básicos).
Perdone la (probable) implementación ligeramente incorrecta, apenas los he usado en comparación con los observables:
public notifications$: BehaviorSubject<NotificationDto[]> = new BehaviorSubject({...});Y empuje sus datos sobre él cuando entre:
(dataResponse: any) => { this.counter = this.dataResponse.length; this.notificationList = this.dataResponse; this.notifications$.next(this.notificationList); },Y tus componentes solo escuchan a ese chico malo:
private sub: any; public ngOnInit(): void { this.sub = this.service.notifications$ .subscribe((x: NotificationDto[]) => this.onNotifications(x)); } public ngOnDestroy(): void { if (this.sub) this.sub.unsubscribe(); } private onNotifications(notifications: NotificationDto[]): void { this.notificationList = notifications; this.count = notifications.length; }Puede suceder si su código se ejecuta fuera de la zona angular. Hijo, puede intentar actualizar su variable dentro de la zona angular y la vista detectará cambios.
constructor(private _ngZone: NgZone) {} fetchNotificationData() { this.myWebSocket = webSocket(this.url); this.myWebSocket.pipe( retry(this.retryConfig)).subscribe( (dataResponse: any) => { // ———-> Here you get inside angular zone this._ngZone.run(() => { this.counter = this.dataResponse.length; this.notificationList = this.dataResponse; }); // Called whenever there is a message from the server (err: any) => console.error("CONNECTION FAILED::", JSON.stringify(err)), // Called if WebSocket API signals some kind of error () => console.log('complete') // Called when connection is closed (for whatever reason) ); }Si no funciona, simplemente puede detectar cambios a la vista.
constructor(private ref: ChangeDetectorRef) fetchNotificationData() { this.myWebSocket = webSocket(this.url); this.myWebSocket.pipe( retry(this.retryConfig)).subscribe( (dataResponse: any) => { this.counter = this.dataResponse.length; this.notificationList = this.dataResponse; // ———-> Force view to detect changes. ref.detectChanges(); }, // Called whenever there is a message from the server (err: any) => console.error("CONNECTION FAILED::", JSON.stringify(err)), // Called if WebSocket API signals some kind of error () => console.log('complete') // Called when connection is closed (for whatever reason) ); }