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.

Author: Luka Jacobowitz, 2016-06-23

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.

 45
Author: Luka Jacobowitz,
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

 19
Author: mtpultz,
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);
  }
 2
Author: Andrei Zhytkevich,
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
});
 0
Author: rinukkusu,
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