2016-06-23 5 views
17

Я начинаю свой проект с Angular2, и разработчики, похоже, рекомендуют RXJS Observable вместо Promises.Простой фильтр по массиву RXJS Observable

Я достиг, чтобы получить список элементов (эпосов) с сервера. Но как я могу отфильтровать эльмы, используя, например, идентификатор?

Следующий код - извлечение из моего приложения и показывает окончательное рабочее решение. Будем надеяться, что это поможет кому-то.

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

Заранее благодарю вас за помощь.

ответ

30

Вы хотите фильтровать фактический массив, а не наблюдаемый, обернутый вокруг него. Таким образом, вы будете отображать содержимое Observable (которое является Epic[]) фильтруемому Epic.

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

Тогда после этого вы можете subscribe к getEpic и делать все, что вы хотите с ним.

+0

Выглядит просто, но: Ошибка: (33, 42) TS2365: Оператор '===' не может применяться к типам «строка» и «номер». Я обновляю вопрос, чтобы показать весь компонент и отношения обслуживания. – Johannes

+0

Ну, если это так, то вы можете просто конвертировать из строки в номер или номер в строку :) –

3

Observables ленивы. Вы должны позвонить subscribe, чтобы сообщить observable, чтобы отправить запрос.

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

Чтобы получить данные, вам необходимо подписаться на Observable, так как http-вызовы асинхронны в 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); 
     } 
    ); 
} 

Вы можете вызвать этот метод, то как это:

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

Вы можете сделать это с помощью flatMap и filter методы Observable вместо метода фильтрации массива JS в map. Что-то вроде:

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 обеспечат особые показатели для фильтрации, а затем вы можете получить с все, что происходит рядом с результатами.

Если машинопись бросает ошибку показывая, что вы не можете сравнить строку и номер независимо от использования == в фильтре просто добавить + перед тем epic.id в фильтре, на угловых документы:

.flatMap(...) 
    .filter((epic) => +epic.id === id) // checks {id: 1}, then {id: 2}, etc 
    .subscribe(...) 
Смежные вопросы