Reputation: 29
OK basically what i want to achieve is an observable that's dependant on another observable, like a joint query. To elaborate more I have two tables, one of activities and another one of the final dates for those activities, so what I'm trying to do is first get the activities and then perform a search for the final dates of those activities, preferably being able to combine both streams to return an array with the activities and final dates in a single new object.
I have tried different implementations without any luck.
Here's how I implement my service.ts (both services for the tables are the same):
private actividadesSubject = new BehaviorSubject([]);
private actividades: ActividadPlaneacion[];
// <------------------------ GET ------------------------>
getActividades(): Observable<ActividadPlaneacion[]>{
return this.actividadesSubject.asObservable();
}
loadActividades(){
var sub = this.http.get(this.url+'select/actividadPlaneacion')
.map(this.extractData)
.catch(this.handleError);
sub.subscribe(
data => this.actividades = data,
err => console.log(err),
() => this.refresh()
);
}
private refresh() {
this.actividadesSubject.next(this.actividades);
}
And the various ways I've tried to achieve this(on the component.ts): MergeMap
this.actividadService.getActividades().mergeMap( actividad =>
this.actividadFechasFinalService.getActividadByIDYear(actividad.ID, actividad.Anio).subscribe( actividades => this.arregloActividadesFlatMap = actividades ));
(This doesn't compile)
FlatMap:
this.actividadService.getActividades().flatMap( actividad => {
this.actividadFechasFinalService.getActividadByIDYear(actividad[0].ID, actividad[0].Anio).subscribe( actividades => this.arregloActividadesFechasFinales = actividades );
return Observable.of(actividad)});
this.actividadService.loadActividades();
This does compiles but doesn't work
And the last one is the closest I've got it to work but I know it's a bad implementation of observables:
this.actividadService.getActividades().flatMap((actividades: any[]) => {
if(actividades.length > 0){
return Observable.forkJoin(
actividades.map((actividad: any) => {
return this.actividadFechasFinalService.getActividadByIDYear(actividad.ID, actividad.Anio)
.map((res: any) => {
let actividadPlaneacion;
console.log(res);
console.log('j = '+this.j);
this.j++;
if(res.length > 0){
res.map( (object) => {
console.log(this.i);
this.i++;
console.log(object);
console.log('object');
//console.log(res[0].FechaFinal);
//let object: any = res;
actividadPlaneacion = new ActividadPlaneacionMasFechasFinales(actividad.ID, actividad.Descripcion, actividad.Nombre, actividad.FechaInicio, actividad.Responsable,
actividad.Practica, actividad.Departamento, actividad.Evidencia, actividad.Producto, object.Actividad, object.FechaFinal, object.Completado, actividad.Anio);
let exists = this.arreglo.find(fecha => fecha.FechaFinal == actividadPlaneacion.FechaFinal);
console.log(exists);
if(exists == undefined)
this.arreglo.push(actividadPlaneacion);
this.arreglo = this.arreglo.sort(function(a, b){
if ( a.FechaFinal < b.FechaFinal )
return -1;
if ( a.FechaFinal > b.FechaFinal )
return 1;
return 0;
});
});
} else{
let existsActividad = this.arreglo.find(fecha => fecha.FechaFinal == actividad.FechaFinal);
console.log(existsActividad);
if(existsActividad == undefined){
actividadPlaneacion = new ActividadPlaneacionMasFechasFinales(actividad.ID, actividad.Descripcion, actividad.Nombre, actividad.FechaInicio, actividad.Responsable,
actividad.Practica, actividad.Departamento, actividad.Evidencia, actividad.Producto, null, null, null, actividad.Anio);
} else {
const index: number = this.arreglo.indexOf(existsActividad);
if (index !== -1) {
this.arreglo.splice(index, 1);
}
} //capitulo
let exists = this.arreglo.find(fecha => fecha.FechaFinal == actividadPlaneacion.FechaFinal);
console.log(exists);
if(exists == undefined)
this.arreglo.push(actividadPlaneacion);
}
return actividadPlaneacion;
});
})
);
}
console.log('FINALLL');
if(actividades.length == 0)
this.getActividades();
return actividades;
}).subscribe(
actividades => this.arregloActividadesFlatMap = actividades
);
this.actividadService.loadActividades();
Another problem that I experienced with this approach is that it doesn't work if the nested obervable returns nothing so I had to do an improvised solution but I'm wondering if flatMap or mergeMap doesn't work if the nested observables return nothing
Upvotes: 0
Views: 290
Reputation: 1899
In order to feed the results of one http call into a second call you can use switchMap, mergeMap, or concatMap.
forkJoin is better suited where you have multiple calls than can run independently and you just want to combine the results of all the calls once they all return.
The option to choose depends on how you want to handle multiple concurrent calls, eg. what happens if the user click the load button multiple times and queues up multiple requests? In summary:
A simple example using switchMap would be:
this.http.get('https://jsonplaceholder.typicode.com/posts')
.switchMap((result) => {
// add your logic here to get data from first request to
// feed to second request
const firstId = result.response[0].id
if (firstId) {
return this.http.get('https://jsonplaceholder.typicode.com/comments/' + firstId);
} else {
// if you don't have what you need return your own observable
return Observable.of('No results');
}
})
.subscribe(result => console.log(result));
Upvotes: 3