Youngjae Youngjae - 2 months ago 25
TypeScript Question

Linq First equivalent to TypsScript+rxjs

I'm familiar with C# Linq, but new to ng2+TypeScript+rxjs development.

In

getDetailByDetailId
method of below code, how to get
First
matched item from observable list?

Models

export class Master {
Id: string;
SomeProperty: string;
Details: Detail[];
}

export class Detail {
DetailId: string;
DetailProperty: string;
}


Methods

getMaster(id:string): Observable<Master>{
return this.http.get(this.webUrl + "/" + id) // web api
.map(this.extractData)
.catch(this.handleError);
}

private extractData(res: Response) {
let body = res.json() as Master[];
return body || [];
}

getDetails(masterId: string): Observable<Detail[]>{
return this.getMaster(masterId)
.map(master => master.Details);
}

getDetailByDetailId(masterId: string, detailId: string): Observable<Detail>{
return this.getDetails(masterId)
.first(d => d.DetailId === detailId); // <-- Error occurred
}


getDetailByDetailId
method gives following two errors.


Error:(47, 16) TS2322: Type 'Observable<Detail[]>' is not assignable to type 'Observable<Detail>'. Type 'Detail[]' is not assignable to type 'Detail'. Property 'DetailId ' is missing in type 'Detail[]'.

Error:(48, 45) TS2339: Property 'DetailId' does not exist on type 'Detail[]'.

Answer

The problem is that getDetails return an Observable<Detail[]>. So the value being emitted to the first method is a Detail[], not a single Detail. What you can do is flatten the array first with flatMap, then you can call first

getDetailByDetailId(masterId: string, detailId: string): Observable<Detail> {
  return this.getDetails(masterId)
    .flatMap(details => details)
    .first((d: Detail) => d.DetailId === detailId);
}