3

I have a service which has an observable which is subscribed to. The payload is passed onto a subject in the service. However, when I subscribe to the subject in my component, nothing is happening. I should see the console.log in the .subscribe method in the ngOnInit in the component.

I had this same setup working with a previous version which subscribed to an observable resulting from a http.get operation. I want to know why its not working with this version.

The service:

@Injectable()
export class TileService {

  availableTiles$ = new Subject<any>();

  // The view is expecing an array, else: Error trying to diff '[object Object]'. Only arrays and iterables are allowed
  source: {}[] = [
    {title: 'Title A'},
    {title: 'Title B'}
  ];

  simpleObservable = new Observable((observer) => {
    observer.next(this.source);
    observer.complete();
});

  constructor() { }

  getTiles(): void {
    this.simpleObservable.subscribe(x => this.availableTilesStream(x));
  }

  availableTilesStream(data) {
    console.log(data);                // Logs an array of the two objects from the source array
    this.availableTiles$.next(data);  // Nothing seems to happen here.
   }

}

The component.ts:

@Component({
  selector: 'app-available-tiles',
  templateUrl: './available-tiles.component.html',
  styleUrls: ['./available-tiles.component.css']
})
export class AvailableTilesComponent implements OnInit {

  tiles: {}[];

  constructor(private tileService: TileService) { }

  ngOnInit() {
    this.tileService.getTiles();
    this.tileService.availableTiles$.subscribe(x => {
      console.log('Log from availableTiles$.subscribe in ngOnInit: ', x);
      this.tiles = x;
    });
  }

}
  • Possible duplicate https://stackoverflow.com/questions/41667580/subject-next-not-firing-in-ngoninit – Venu Duggireddy Apr 24 '18 at 21:58
  • 2
    The the emit happen before you subscribe to the subject? any new subscriber won't receive the emit unless you are using a behaviorsubject. – Ringo Apr 25 '18 at 00:13

1 Answers1

17

Like Ringo said, the component most likely subscribes after data has been passed (via .next()) to the availableTiles$ Subject.

Seeing as you're using Subject, late subscribers won't receive a value until .next() has been called on the source Subject again.

One solution is to use BehaviorSubject. This means that any subscriber (including late ones) will immediately receive a value.

@Injectable()
export class TileService {

   availableTiles$ = new BehaviorSubject<any>([]); // must be initialised with a value
Rich
  • 882
  • 1
  • 8
  • 19
  • Thank you @Ringo and and @Rich. That works. What threw me is that in my `http.get` version i'm using `subject` and I'm creating the observable and subscribing all on one line so in my mind the the observable was populated then subscribed to. However, that probably isn't the case since, even though the json file targeted by the http.get is local, the subscribe is actually happening before the observable is populated: `this.http.get(this.tilesUrl).subscribe(tiles =>{this.availableTilesStream(tiles);` –  Apr 25 '18 at 17:00
  • 1
    The subscription happens before any value is emitted. Remember that a Observable doesn't execute until it's subscribed to - that's important. So if you removed that subscription you wouldn't see that http request fire in your Dev tools. – Rich Apr 25 '18 at 19:21