Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 924
Tunity Avatar asked Aug 01 '16 23:08

Tunity


2 Answers

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.

like image 63
acdcjunior Avatar answered Oct 22 '22 06:10

acdcjunior


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

ypurComponent.html

(yourObservable | async | slice :0:1)
like image 20
Ankit Rathore Avatar answered Oct 22 '22 06:10

Ankit Rathore