Luciano Pinheiro
Posted on October 16, 2023
The problem
I have data coming from a socket.io server. Every new arriving message is sent to an array. I'm using a Service to keep all my data. It allows me to share the data among components.
// app.component.ts
constructor(
private webSocketService: WebSocketService,
private data: SessionDataService
) {
this.socket.on('balance', (message: any) => {
this.data.setBalance(JSON.parse(message));
});
}
// session-data.service.ts
export class SessionDataService {
setBalance(balance: any) {
this.balance = balance;
this.balance_history.push(balance);
}
}
At some point, I needed a graph to plot that history. I made a new component and put my data there, but it didn't work. Why? The update happened only at beginning of the Component.
// wallet component
// doesn't work
export class WalletComponent {
balance_history: any[] = [];
constructor(data: SessionDataService) {
balance_history = data.balance_history;
}
}
The solution
If we need to get the updated version, we need to subscribe the data through a Observer. So, it will update every time the value changes. Remember that if you leave the component, the data will be destroyed. So, we must keep all the data in the service.
The solution is something like this:
// wallet component uses service
export class WalletComponent {
// define data that will be shown in the template
plot_data: any[] = [];
constructor(data: SessionDataService) {
// subscribe to the observable
data.wallet_history.subscribe((balance) => {
// every time there is a new message,
// we update service data and local variable
this.update_plot_data();
});
}
update_plot_data() {
// data in format plotly will understand
this.plot_data = {
data: [
{
x: this.data.balance_history.map((_: number, index: number) => index),
y: this.data.balance_history,
type: 'scatter',
mode: 'lines+points',
marker: { color: 'red' },
},
],
};
}
}
// service SessionDataService
export class SessionDataService {
wallet: any = {};
balance_history: any = [];
messages: string[] = [];
// make observable
private wallet_historySource = new BehaviorSubject({});
public wallet_history = this.wallet_historySource.asObservable();
// when receive a websocket message from server,
//
setWallet(wallet: any) {
this.wallet = wallet;
this.balance_history.push(wallet.balance);
this.wallet_historySource.next(wallet.balance);
}
}
A variation of this solution is to keep plot_data
inside SessionDataService so you don't have to use observable. Maybe it's in fact a better solution for this case, but I could not show the subscription feature.
Posted on October 16, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.