Filtro simple en matriz de RXJS Observable
Estoy comenzando mi proyecto con Angular2 y los desarrolladores parecen recomendar RXJS Observable en lugar de Promises.
He conseguido recuperar una lista de elementos (epics) del servidor. Pero, ¿cómo puedo filtrar los elementos usando, por ejemplo, un id?
El siguiente código es una extracción de mi aplicación y muestra ahora la solución de trabajo final. Esperemos que ayude a alguien.
@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;
}
Gracias de antemano por su ayuda.
4 answers
Querrá filtrar el array real y no el observable envuelto alrededor de él.
Así que mapearás el contenido del Observable (que es un Epic[]
) a un Epic
filtrado.
getEpic(id:number): Observable<Epic> {
return this.getEpics()
.map(epics => epics.filter(epic => epic.id === id)[0]);
}
Luego puedes subscribe
a getEpic
y hacer lo que quieras con él.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-23 12:42:58
Puede hacer esto usando los métodos flatMap
y filter
de Observable
en lugar del método de filtro de matriz JS en map
. Algo como:
this.getEpics()
.flatMap((data) => data.epics) // [{id: 1}, {id: 4}, {id: 3}, ..., {id: N}]
.filter((epic) => epic.id === id) // checks {id: 1}, then {id: 2}, etc
.subscribe((result) => ...); // do something epic!!!
flatMap
proporcionará índices singulares para filtrar y luego puede continuar con lo que suceda a continuación con los resultados.
Si TypeScript lanza un error que indica que no puede comparar una cadena y un número independientemente de su uso de ==
en el filtro, simplemente agregue un +
antes de epic.id
en el filtro, por el Angular docs:
.flatMap(...)
.filter((epic) => +epic.id === id) // checks {id: 1}, then {id: 2}, etc
.subscribe(...)
Ejemplo:
Https://stackblitz.com/edit/angular-9ehje5?file=src%2Fapp%2Fapp.component.ts
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-11 17:58:37
Observables
son perezosos. Tienes que llamar a subscribe
para decirle a un observable
que envíe su solicitud.
getEpic(id:number) {
return this.getEpics()
.subscribe(x=>...)
.filter(epic => epic.id === id);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-23 12:42:46
Tienes que suscribirte a Observable
s para obtener los datos, ya que las llamadas http son asincrónicas en 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);
}
);
}
Puedes llamar a ese método así:
this.someService.getEpic(epicId, (epic: Epic) => {
// do something with it
});
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-23 12:43:07