8
votes

I start to build an application. There are a lot of components. Each of them need a part of data from 1 webSocket. The example of a receiveing object by webSocket:

enter image description here

Each Angular 2 component need 1 field from receiveing object. Is it possible to make 1 service, that will connect to webSocket, receive data and share it between all components ? I think it will be a good solution.

Now i'm using the next approach:

getConfigCallback() {
    this.connectionSockets.telemetry = io(this.config.connections.telemetry);
    this.connectionSockets.controlFlow = new WebSocket(this.config.connections.controlFlow.server + ':' + this.config.connections.controlFlow.port);

    this.connectionSockets.telemetry.on('telemetry', function(data) {
        console.log(data);
    });

    this.connectionSockets.controlFlow.onopen = function(data) {
        console.log('onOpen', data);
    };

    this.connectionSockets.controlFlow.onmessage = function(data) {
        console.log('onMessage', data);
    };
}

I receive data in a main component and want to share it between components using component's instances. But i think it's a bad idea and there is exist a better solution.

2
You could add the service to your bootstrap() command where you setup your providers. Then in your components get the service via dependency injection from the constructor. Now you can use the service in every component you inject it.rinukkusu

2 Answers

6
votes

Sure you can share your service by set its provider when bootstrapping the application:

bootstrap(AppComponent, [ WebSocketService ]);

This way you will share the same instance of your service in the whole application. I mean when you inject the WebSocketService service, the corresponding instance will be the same whatever the component / service.

To be able to share the received data, I would leverage an hot observable. By default observables are cold so you need to use the share operator.

initializeWebSocket(url) {
  this.wsObservable = Observable.create((observer) => {
    this.ws = new WebSocket(url);

    this.ws.onopen = (e) => {
      (...)
    };

    this.ws.onclose = (e) => {
      if (e.wasClean) {
        observer.complete();
      } else {
        observer.error(e);
      }
    };

    this.ws.onerror = (e) => {
      observer.error(e);
    }

    this.ws.onmessage = (e) => {
      observer.next(JSON.parse(e.data));
    }

    return () => {
      this.ws.close();
    };
  }).share();
}

Components that would like to receive data from the web socket could use this observable this way:

@Component({
  (...)
})
export class SomeComponent {
  constructor(private service:WebSocketService) {
    this.service.wsObservable.subscribe((data) => {
      // use data
    });
  }
}

See this article for more details in the "event-based approach" section:

0
votes

Something like the following (depending on your concrete requirements):

@Injectable()
class WsService {
  comp1Data = new BehaviorSubject();
  comp2Data = new BehaviorSubject();

  constructor() {
    getData().subscribe( val => {
      ...
      this.compXData.next(someValue);
    });
  }
  ...
}
@Component({...}) 
export class Component1 {
  constructor(wsService:WsService) {
    wsService.comp1Data.subscribe(value => this.data = value);
  }
}
@NgModule({
   directives: [AppComponent, Component1],
   bootstrap: [AppComponent],
   providers: [WsService, ...]
});