26

I am trying to subscribe to an observable from a service, it builds without error but I get the error "this.service.getBanners(...).subscribe is not a function" when viewing in the browser.

Service:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

@Injectable()

export class BannerService {

    banners: any = ['1','2','3'];

    constructor(
    ) {}

    getBanners(): Observable<any[]> {
        return this.banners;
    }

    setBanners(banners: any[]): void {
        this.banners = banners;
    }

}

Component:

import { Component, ViewEncapsulation, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { BannerService } from './../banner/banner.service';

@Component({
    selector: '.banner',
    templateUrl: './banner.component.html',
    styleUrls: ['./banner.component.sass'],
    encapsulation: ViewEncapsulation.None
})

export class BannerComponent implements OnInit {

    banners: any[];

    constructor(private bannerService: BannerService){

    }

    ngOnInit() {
        this.bannerService.getBanners().subscribe(banners => this.banners = banners);
    }
}

Any ideas what I am doing wrong?

isherwood
  • 58,414
  • 16
  • 114
  • 157
Steve
  • 4,314
  • 3
  • 16
  • 21

2 Answers2

41

You should return an observable , instead you are returning an array:

For Angular <= 5.x.x

getBanners(): Observable<any[]> {
    return Observable.of(this.banners);
}

For Angular >= 6.x.x

getBanners(): Observable<any[]> {
    return of(this.banners);
}

Reference

leonardofmed
  • 842
  • 3
  • 13
  • 47
Sajeetharan
  • 216,225
  • 63
  • 350
  • 396
  • Thanks, this fixed the error. I also changed the imports as recommended by Yakov Fain in his answer and imported import 'rxjs/add/observable/of' too. I have an *ngFor with an async pipe but it doesn't update when I call setBanners and change the contents of the banners array. – Steve Aug 16 '17 at 09:20
6

A couple of things to fix.

  1. You declare that your function getBanners() returns an Observable, but you return an array. So change your return statement to

    return Observable.from(this.banners);

You'll also need to add this:

import 'rxjs/add/observable/from'; 
  1. This is bad practice and will include the entire rxjs library into your code:

    import { Observable } from 'rxjs';

Import only what you need. Replace the above with

import { Observable } from 'rxjs/Observable'; 
Yakov Fain
  • 11,972
  • 5
  • 33
  • 38
  • Thanks, I did have the import like this originally but I removed it when testing, I have changed it back. For some reason I was getting an error when using Observable.from so I changed it to Observable.of as suggested by Sajeetharan and that fixed the error. – Steve Aug 16 '17 at 09:22
  • 1
    It seems that point 2 has changed recently, see: [RxJS 6 Changes - Overview "Import Statement](https://www.academind.com/learn/javascript/rxjs-6-what-changed/#import-statement-update-path). – insertusernamehere Sep 18 '18 at 16:57
  • 1
    True, I blogged about RxJS 6 here: https://yakovfain.com/2018/05/02/rxjs-essentials-part-9-dealing-with-breaking-changes-in-rxjs-6/ – Yakov Fain Sep 19 '18 at 13:16