'Observable emits no value
I am new to Observables. I am using a switchMap to loop through an array of Observables from firestore, retriving two streams, combining the outputs of the streams into a new Observable Array.
createSuperPolicy( product:VehicleProducts, vehicle:Vehicle, id:String, policyCertID:String) : Observable<SuperVehiclePolicy>{
var temp = new SuperVehiclePolicy;
temp.policyID = id,
temp.vendor = product.vendor,
temp.title = product.title,
temp.premium = product.premium,
temp.offer = product.offer,
temp.reg = vehicle.registrationNumber ,
temp.benefits = product.Benefits,
temp.policyCertID = policyCertID
return of(temp)
}
populateVehiclePolicyList = this.vehiclePolicyService.getPolicies().pipe(
switchMap((policies:VehiclePolicy[]) => {
var policyList$: Observable<SuperVehiclePolicy>[] = [];
policies.forEach(policy => {
var product$: Observable<VehicleProducts> = this.vehicleProductService.getProductByID(policy.vehicleProductID)
var vehicle$: Observable<Vehicle> = this.vehicleService.getVehicleByID(policy.vehicleID)
var id$ = of(policy.id)
var certID$ = of(policy.policyCertID)
combineLatest(product$, vehicle$, id$,certID$)
.pipe(map(([product, vehicle, pid,certID]) => this.createSuperPolicy(product,vehicle, pid, certID)))
.subscribe((val) => policyList$.push(val));
});
console.log(policyList$)
return forkJoin(policyList$);
})
)
Calling viewing the contents of the new Array of Observables(policyList$) displays the contents of the array.
Now when I subscribe to populateVehiclePolicyList, as below,
this.displayService.populateVehiclePolicyList.subscribe(((policy: SuperVehiclePolicy[]) => {console.log(policy)}))
Console.log(policy) returns neither a value nor an error. I am confused as to what is happening. How can I successfully subscribe to populateVehiclePolicyList, so as to consume the output?
Solution 1:[1]
there are few issues in your code so before I share the proper code, let me explain them a lil bit:
return temp as unknown as Observable<SuperVehiclePolicy>
as keyword doesn't actually cast to different types, it just tells typescript to treat one thing as something other so you can't cast a variable of type SuperVehiclePolicy into Observable<SuperVehiclePolicy> like this, typescript won't complain as you are using as but you'll get problems in runtime, for this purposes rxjs provides an operator called of that you did use inside that switchMap
you are first converting your object to unknown so that you can then convert it to Observable<SuperVehiclePolicy>, that's just wrong cuz by doing this, you're basically hiding the symptoms instead of curing the disease.
var policyList$: Observable<SuperVehiclePolicy>[] = [];
don't use var, it's dead, use either let or const, read this
combineLatest(product$, vehicle$, id$,certID$)
.pipe(map(([product, vehicle, pid,certID]) => this.createSuperPolicy(product,vehicle, pid, certID)))
.subscribe((val) => policyList$.push(val));
you are subscribing manually inside switchMap, don't do that, generally don't subscribe inside an rxjs operator as most of the time this is not what you actually want to do.
now why doesn't console.log(policy) logs anything?
you are providingforkJoin(policyList$); to your switchMap which is good but because you subscribing manually to above mentioned combineLatest, switchMap didn't wait for it and by the time you started pushing inside policyList$, your switchMap was already done. Hope this helps you understand why subscribing inside an operator is sometimes not what you actually want.
Ok lets jump onto the right code:
class DisplayService {
createSuperPolicy(product: VehicleProducts, vehicle: Vehicle, id: String, policyCertID: String): SuperVehiclePolicy {
const temp = new SuperVehiclePolicy();
temp.policyID = id;
temp.vendor = product.vendor;
temp.title = product.title;
temp.premium = product.premium;
temp.offer = product.offer;
temp.reg = vehicle.registrationNumber;
temp.benefits = product.Benefits;
temp.policyCertID = policyCertID;
return temp;
}
populateVehiclePolicyList = this.vehiclePolicyService.getPolicies().pipe(
switchMap((policies: VehiclePolicy[]) => {
const policyList$: Observable<SuperVehiclePolicy>[] = policies.map(policy => {
const product$: Observable<VehicleProducts> = this.vehicleProductService.getProductByID(policy.vehicleProductID);
const vehicle$: Observable<Vehicle> = this.vehicleService.getVehicleByID(policy.vehicleID);
// build super policy for current policy and return it in an observable
return forkJoin([product$, vehicle$]).pipe(
map((product, vehicle) => this.createSuperPolicy(product, vehicle, policy.id, policy.policyCertID))
);
});
return forkJoin(policyList$).pipe(
tap(superPolicies => {
console.log("Super policies: ", superPolicies);
})
);
})
);
}
notice that you don't need to return Observable<SuperVehiclePolicy> from createSuperPolicy
let me know if you have any doubt regarding above code, Happy coding!
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Yogi |
