-1

I have an angular service and two different unrelated components that use this service:

Service Code:

const url = 'ws://localhost:8080

@Injectable({
   provideIn: 'root',
})

export class MyService{

  public subject: Subject<Status>;

  constructor(wsService: WebSocketService){
    this.subject = <Subject<Status>>wsService.connect(url).map(
       (response: MessageEvent): Status => {
          let data = JSON.parse(response.data);
          return data;
        }
    );
  }

  getObs(){
    return this.subject.asObservable();
  }

  sendMsg(msg){
    this.subject.next(msg);
  }

}

Component 1:

@Component

.. some irrelevant code ..

constructor(private service: MyService){
  this.service.getObs().subscribe( data => 
    console.log('comp1');
  );

  console.log('comp1 - after subscribe');
}

.. some irrelevant code ..

Component 2:

@Component

.. some irrelevant code ..

constructor(private service: MyService){
  this.service.getObs().subscribe( data => 
    console.log('comp2');
  );

  console.log('comp2 - after subscribe');
}

.. some irrelevant code ..

I get the following output in the console:

comp1

comp1 - after subscribe

comp2 - after subscribe

the output I think I should get:

comp1

comp1 - after subscribe

comp2

comp2 - after subscribe

Can anyone explain what the problem is?

Note: I added my service to the Module providers and got the same result.

Thanks.

here's the code for webSocketService: https://github.com/elliotforbes/ng-chat/blob/master/src/app/common/services/websocket.service.ts

Kurt Hamilton
  • 12,490
  • 1
  • 24
  • 40
Natalie
  • 71
  • 4

2 Answers2

1

You Can use Behaviour Subject Instead of Normal Subject.

https://medium.com/@luukgruijs/understanding-rxjs-behaviorsubject-replaysubject-and-asyncsubject-8cc061f1cfc0

Amar Bisht
  • 137
  • 6
  • We don't know what kind of subject is being used - it's just being cast to a `Subject` - that doesn't mean that it is actually a normal `Subject`. We need more information about the code. – Kurt Hamilton Mar 09 '20 at 07:53
  • https://alligator.io/rxjs/subjects/ For details about subjects. It's sure that it's not a behavior Subject. You can use behavior Subject as below. ` private categories: BehaviorSubject = new BehaviorSubject({});` – Amar Bisht Mar 09 '20 at 07:58
  • I'm well aware of the different types of subject. OP clearly needs a `ReplaySubject`, as there is no initial state. But we don't know what `wsService.connect(url)` returns, so any answers would only be guesses – Kurt Hamilton Mar 09 '20 at 08:00
1

You should take control of your own subjects rather than piggybacking on WebSocketService.connect and assuming that you're going to get the desired behaviour.

From the link to the source code of WebSocketService that you posted, we see that it is a plain subject. The functionality you desire - emitting a value upon subscription (providing one exists) - is provided by ReplaySubject.

You should declare a local ReplaySubject, which is what your components will subscribe to. You would then subscribe to your WebSocketService. Any responses that come from the WebSocketService will be mapped to a status and then sent to your local subject.

const url = 'ws://localhost:8080

@Injectable({
   provideIn: 'root',
})

export class MyService{

  // Declare local ReplaySubject that emits the last value upon subscription
  private subject: Subject<Status> = new ReplaySubject<Status>(1);

  constructor(wsService: WebSocketService) {
    // Subscribe to the web socket service.
    // Subscribing in constructors is fairly bad practice, 
    // although you can get away with it in singleton services
    wsService.connect(url).pipe(
      // map responses to statuses
      map((response: MessageEvent): Status => {
        let data = JSON.parse(response.data);
        return data;
      })
    ).subscribe((status: Status) => {
      // send the status to all subscribers
      this.subject.next(status);
    });
  }

  getObs(): Observable<Status> {
    return this.subject.asObservable();
  }

  sendMsg(msg): void {
    this.subject.next(msg);
  }
}
Kurt Hamilton
  • 12,490
  • 1
  • 24
  • 40