0

I'm trying to use Subject and a shared service to transfer data from one component to another. But it isn't working.

Please note that I listed the service in the module level instead of the component decorator. Also perhaps worth noting is that these two components do not share a parent-child relationship.

My service (SearchService):

import { Subject } from 'rxjs/Subject';

@Injectable()
export class SearchService {
  public messageSource = new Subject<any>();

  constructor() { }

  topAlbums(album){
    this.messageSource.next(album);
  }

}

Component 1 (That is sending the data). When createList() is triggered, it navigates to the new route perfectly but the message that I'm subscribing to below (in Component 2) does not show.

    import { SearchService } from '../../services/search.service';

    export class AlbumComponent implements OnInit {
    private UNIQUE_ID: string;
    constructor(private _service: SearchService, private _http: Http, private router: Router) { }

    //Linked to a click event handler
    createList(){
        //API Call to retrieve an ID
        this._http.post('https://api.url', data)
            .map(res => res.json())
            .subscribe(item => {
              this.ID = item.id;
              let parsed_JSON = JSON.parse(item.files.myAlbums.content);
              this.router.navigate(['/list', this.UNIQUE_ID]);
            })
       this._service.topAlbums("Testing out by sending a dummy message");

 }

Component 2 (Receiving the data):

import { SearchService } from '../../services/search.service';

    export class ListComponent implements OnInit {
    constructor(private _service: SearchService) { }
    ngOnInit(){
      this._service.messageSource.subscribe(data => console.log(data));
    }          
 }
blankface
  • 5,757
  • 19
  • 67
  • 114

1 Answers1

3

I think that happens because you are subscribing to the Subject in your ListComponent after you emitted a value using next(). Use a BehaviorSubject instead. When subscribing to a BehaviorSubject it emits its last value. Because of that it also needs to have an initial value:

let bSubject = new BehaviorSubject(null);

bSubject.next(album);

bSubject
 .filter(value => value !== null) // filter out the initial null value to avoid problems if you did not emit anything before subscribing
 .subscribe((value) => {
  console.log(value); // logs your album
 }

Here is a great post on exactly that topic.

David
  • 7,387
  • 3
  • 22
  • 39
  • Beautiful! Works perfectly now. Also thanks for that post. So when would you choose Subject over BehaviorSubject? Seems like the latter is the way to go when passing data around components. – blankface Sep 09 '17 at 13:15
  • Great, glad I could help you! Use a Subject when you are only interested in the values emitted by the source starting at the point of subscription. If you also need the last value emitted before subscription (like in your case) use a BehaviourSubject. – David Sep 09 '17 at 13:23