DEV Community

Luciano Pinheiro
Luciano Pinheiro

Posted on • Edited on

Update plotly.js data in Angular

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);
  }
}

Enter fullscreen mode Exit fullscreen mode

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;    
  }
}
Enter fullscreen mode Exit fullscreen mode

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);
  }

}
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)