2016-06-23 12 views
17

Rozpoczynam mój projekt z Angular2, a programiści wydają się zalecać RXJS Observable zamiast Promises.Prosty filtr na macie RXJS Observable

Osiągnąłem, aby pobrać listę elementów (eposów) z serwera. Ale jak mogę filtrować elments, używając na przykład identyfikatora?

Poniższy kod jest ekstrakcją z mojej aplikacji i pokazuje teraz ostateczne rozwiązanie robocze. Miejmy nadzieję, że to pomoże komuś.

@Injectable() 
export class EpicService { 

    private url = CONFIG.SERVER + '/app/'; // URL to web API 

    constructor(private http:Http) {} 

    private extractData(res:Response) { 
    let body = res.json(); 
    return body; 
    } 

    getEpics():Observable<Epic[]> { 
    return this.http.get(this.url + "getEpics") 
     .map(this.extractData) 
     .catch(this.handleError); 
    } 

    getEpic(id:string): Observable<Epic> { 
    return this.getEpics() 
     .map(epics => epics.filter(epic => epic.id === id)[0]); 
    } 
} 

export class EpicComponent { 

    errorMessage:string; 
    epics:Epic[]; 
    epic:Epic; 

    constructor(
    private requirementService:EpicService) { 
    } 

    getEpics() { 
    this.requirementService.getEpics() 
     .subscribe(
     epics => this.epics = epics, 
     error => this.errorMessage = <any>error); 
    } 

    // actually this should be eventually in another component 
    getEpic(id:string) { 
    this.requirementService.getEpic(id) 
     .subscribe(
     epic => this.epic = epic, 
     error => this.errorMessage = <any>error); 
    } 
} 

export class Epic { 
    id: string; 
    name: string; 
} 

Z góry dziękuję za pomoc.

Odpowiedz

30

Będziesz chciał filtrować rzeczywistą tablicę, a nie otaczającą ją obserwowalną. Więc zamapujesz zawartość Observable (która jest Epic[]) na przefiltrowaną Epic.

getEpic(id:number): Observable<Epic> { 
    return this.getEpics() 
    .map(epics => epics.filter(epic => epic.id === id)[0]); 
} 

Następnie potem można subscribe do getEpic i robić, co chcesz z nim.

+0

Wygląda prosto, ale: Błąd: (33, 42) TS2365: Operator '===' nie może być zastosowany do typów 'string' i 'number'. Uaktualnię pytanie, aby pokazać cały komponent i relację serwisową. – Johannes

+0

Jeśli tak, to możesz po prostu przekonwertować ciąg znaków na liczbę lub liczbę na ciąg znaków :) –

3

Observables są leniwe. Musisz zadzwonić pod numer subscribe, aby powiadomić observable o wysłaniu żądania.

getEpic(id:number) { 
    return this.getEpics() 
      .subscribe(x=>...) 
      .filter(epic => epic.id === id); 
    } 
0

Musisz subskrybować na Observable s, aby uzyskać dane, ponieważ połączenia HTTP są asynchroniczne w JavaScript.

getEpic(id: number, callback: (epic: Epic) => void) { 
    this.getEpics().subscribe(
     epics: Array<Epic> => { 
      let epic: Epic = epics.filter(epic => epic.id === id)[0]; 
      callback(epic); 
     } 
    ); 
} 

można wywołać tej metody wtedy tak:

this.someService.getEpic(epicId, (epic: Epic) => { 
    // do something with it 
}); 
9

Można to zrobić za pomocą flatMap i filter metod Observable zamiast JS metodę filtrowania tablicy w map. Coś jak:

this.getEpics() // [{id: 1}, {id: 4}, {id: 3}, ..., {id: N}] 
    .flatMap((data) => data.epics) 
    .filter((epic) => epic.id === id) // checks {id: 1}, then {id: 2}, etc 
    .subscribe((result) => ...); // do something epic!!! 

flatMap zapewni osobliwe indeksy filtrowania, a następnie można dostać się z tym, co dzieje się dalej z wyników.

Jeśli maszynopis wyrzuca błąd wskazujący, że nie można porównać ciąg i numer niezależnie od stosowania == w filtrze wystarczy dodać + przed epic.id w filtrze, za kątowego docs:

.flatMap(...) 
    .filter((epic) => +epic.id === id) // checks {id: 1}, then {id: 2}, etc 
    .subscribe(...)