Phil
Phil

Reputation: 43

Angular 6 'rxjs/Rx'; observable first() dont work

I have created a service that retrieves data from a mock as follows:

export const PHOTOS: Photo[] = [
 {   
    title: "title 1",
    srcImage:"https:/34297040313_3436fd2556_k.jpg"        
  },
  { 
    title: "title 2",               
    srcImage:"https://34297040313_3436fd2556_k.jpg"                   
  }
}

The service is below

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Photo } from '../../model/photo';
import { PHOTOS } from './mock-photos';
import { of } from 'rxjs/observable/of';

@Injectable()
export class PhotoService {

  constructor() { }

  getPhotos(): Observable<Photo[]> {
    return of(PHOTOS);
  }    
}

And in my component I use the service as follows:

      getPhotos(): void {
        this.photoService.getPhotos().first()
   .subscribe(response => console.log(response));
      }

I would expect to display only the first element and not all of the list.

Upvotes: 1

Views: 3979

Answers (3)

a better oliver
a better oliver

Reputation: 26848

As the others have already noted the element emitted by the stream is the array.

The simplest solution is to add one more operator:

this.photoService
  .getPhotos()
  .flatMap(photos => photos)
  .first()
  .subscribe(response => console.log(response));

Or in RxJS 6:

this.photoService
  .getPhotos()
  .pipe(
    flatMap(photos => photos),
    first()
  )
  .subscribe(response => console.log(response));

flatMap allows you to return an array without creating an observable first. It emits all entries of the array individually (like you had expected it in the beginning).

Upvotes: 2

martin
martin

Reputation: 96969

When you use of(PHOTOS) it takes the entire array and emits it as a single item.

If you want getPhotos() to emit each array item as a single emission you can use from(PHOTOS).

You can also use map to get only the first item or you can take the first item in subscriptions:

from(PHOTOS)
  .subscribe(photos => {
    // photos[0]
  });

from(PHOTOS)
  .pipe(
    first(),
  )
  .subscribe(photo => {
    // photo
  });

Upvotes: 1

Adrian F&#226;ciu
Adrian F&#226;ciu

Reputation: 12572

PHOTOS is an array so when you do of(PHOTOS) it will create an observable that will emit that array as the first value. When you use the first method it will work, meaning it will return only the first item emitted by the observable, but in this case it's an array with all the values.

If you want to create an observable that will emit individual items from each item in the array you need to use the from method from(PHOTOS). In this case first will work as you expect.

Upvotes: 3

Related Questions