Using first() operator on an observable to get the first element

21,907

Solution 1

When you use .map(), its argument is the type of the Observable.

Since the one you have in your service is an Observable<Member[]>, then processArray in

.map(processArray => {
   return processArray.filter(x=> x.type === "member")
   //.first()
})

is an array - a Member[].

Thus that .filter() you are calling is Array#filter() not Observable#filter().

The same way the .first() you would be calling would be Array#first() not Observable#first().

Since Array does not have a .first() array, it yields a runtime error (see plunker).


Going further, if you instead call .first() at the Observable, you wouldn't see much difference, since it is an Observable<Member[]>, it would get the first element of that Observable which is the whole array.


Solutions:

If you really want it to keep being an Observable<Member[]> and retrieve just the first member, you could do (see plunker):

.map(processArray => {
  console.log('pa2', typeof processArray);
  return [ processArray.filter(x=> x.type === "member")[0] ] // <-- [0] to get first item
                                    // wrap the result in [ ]s, because it expects an array
})

Though what I advise you to do is to turn the observable into an Observable<Member> (instead of Observable<Member[]>). You can do that using .mergeMap()/.flatMap().

app/member.service.ts

import 'rxjs/add/operator/mergeMap'; // <------------------ add this import

getMembers (): Observable<Member> { // <----------- changed from Member[] to Member
  var one = this.http.get(this.memberUrl)
    .map( this.extractData )
    .mergeMap(processArray => {  // <----------------- map to mergeMap
      return processArray.filter(x=> x.type === "member")
    }).first()                   // <----------------------- now you can use .first()

app/member-list.component.ts

import 'rxjs/add/operator/toArray'; // <------------------ add this import
...
getMembers() {
  this.memberService.getMembers().toArray() // <-------------- add .toArray()
                 .subscribe(

See final demo plunker here.

Solution 2

I was able to access the Observable's first member by using angular's async pipe.

ypurComponent.html

(yourObservable | async | slice :0:1)
Share:
21,907
Admin
Author by

Admin

Updated on August 11, 2022

Comments

  • Admin
    Admin over 1 year

    I am kind of new to RxJS, In this plunk I am trying to return the first member in the array, I have tried the first() operator but it returns nothing:

    var one = this.http.get(this.memberUrl)
      .map( this.extractData )
      .map(processArray => {
      return processArray.filter(x=> x.type === "member")
      //.first()
      })
    

    Whats wrong with the commented line in app/member.service.ts?