2016-06-23 3 views
17

Ich beginne mein Projekt mit Angular2 und die Entwickler scheinen RXJS Observable statt Promises zu empfehlen.Einfacher Filter auf Array von RXJS Observable

Ich habe erreicht, eine Liste von Elementen (Epen) vom Server abzurufen. Aber wie kann ich die Elemente filtern, indem ich zum Beispiel eine ID verwende?

Der folgende Code ist eine Extraktion aus meiner App und zeigt nun die endgültige Arbeitslösung. Hoffen wir, dass es jemandem hilft.

@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; 
} 

Vielen Dank im Voraus für Ihre Hilfe.

Antwort

30

Sie wollen das tatsächliche Array und nicht die Observable um es zu filtern. So werden Sie den Inhalt der Observable (die eine Epic[] ist) auf eine gefilterte Epic zuordnen.

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

Dann danach können Sie subscribe-getEpic und tun, was man will.

+0

Sieht einfach aus, aber: Fehler: (33, 42) TS2365: Operator '===' kann nicht auf die Typen 'String' und 'Nummer' angewendet werden. Ich werde die Frage aktualisieren, um die gesamte Komponenten- und Service-Beziehung zu zeigen. – Johannes

+0

Nun, wenn es das ist, dann kannst du einfach von String in Zahl oder Nummer in String umwandeln :) –

3

Observables sind faul. Sie müssen subscribe anrufen, um eine observable zu senden, um seine Anfrage zu senden.

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

Sie müssen auf Observable s abonnieren, um die Daten zu erhalten, da http Aufrufe in JavaScript async sind.

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); 
     } 
    ); 
} 

können Sie diese Methode aufrufen, dann wie folgt aus:

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

Sie dies tun, können die flatMap und filter Methoden der Observable anstelle des JS-Array-Filter-Methode in map verwenden. Etwas wie:

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 werden singuläre Indizes für die Filterung zur Verfügung stellen und dann können Sie erhalten auf mit dem, was mit den Ergebnissen als nächstes passiert.

Wenn Typoskript wirft einen Fehler anzeigt, dass Sie nicht einen String und eine Zahl unabhängig von Ihrer Verwendung von == im Filter fügen Sie einfach ein + vor epic.id im Filter nach dem Angular docs vergleichen können:

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