Простой фильтр на массиве RXJS Observable
Я начинаю свой проект с Angular2, и разработчики, похоже, рекомендуют RXJS Observable вместо Promises.
Я достиг, чтобы получить список элементов (эпосов) с сервера.
Но как я могу отфильтровать эльмы, используя, например, идентификатор?
Следующий код - это извлечение из моего приложения и теперь показывает окончательное рабочее решение. Пусть надеется, что это поможет кому-то.
@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;
}
Заранее благодарим вас за помощь.
Ответы
Ответ 1
Вам нужно будет фильтровать фактический массив, а не наблюдаемый, обернутый вокруг него.
Таким образом, вы сопоставляете содержимое Observable (которое является Epic[]
) с фильтрованным Epic
.
getEpic(id:number): Observable<Epic> {
return this.getEpics()
.map(epics => epics.filter(epic => epic.id === id)[0]);
}
Затем вы можете subscribe
до getEpic
и делать с ним все, что хотите.
Ответ 2
Вы можете сделать это, используя методы 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
предоставит сингулярные индексы для фильтрации, а затем вы сможете продолжить то, что произойдет дальше с результатами.
Если TypeScript выдает ошибку, указывающую, что вы не можете сравнивать строку и число, независимо от использования ==
в фильтре, просто добавьте до epic.id
в фильтр, за Angular docs:
.flatMap(...)
.filter((epic) => +epic.id === id) // checks {id: 1}, then {id: 2}, etc
.subscribe(...)
Ответ 3
Observables
ленивы. Вы должны позвонить subscribe
, чтобы сообщить observable
отправить запрос.
getEpic(id:number) {
return this.getEpics()
.subscribe(x=>...)
.filter(epic => epic.id === id);
}
Ответ 4
Вам нужно подписаться на 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
});