Búsqueda de sitios web

javascript - Filtro simple en un array de Observable de RXJS


Estoy comenzando mi proyecto con Angular2 y los desarrolladores parecen recomendar RXJS Observable en lugar de Promises.

He logrado recuperar una lista de elementos (épicas) 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 final que funciona. 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 tu ayuda.

Respuesta #1

Querrás filtrar el arreglo real y no el observable que lo envuelve. Así que mapearás el contenido del Observable (que es un Epic[]) a un Epic filtrado.

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

Luego, después puedes subscribe a getEpic y hacer lo que quieras con ello.

Respuesta #2

Puedes hacer esto usando los métodos flatMap y filter de Observable en lugar del método filter de array de JS en map. Algo así:

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 filtrado y luego puedes continuar con lo que ocurra después con los resultados.

Si TypeScript lanza un error indicando que no puedes comparar una cadena y un número sin importar tu uso de == en el filtro, simplemente agrega un + antes de epic.id en el filtro, según la documentación de Angular:

    .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

Artículos relacionados