I have three services that return observables. The first returns a list of recipes, the second gets all ingredients for a given recipe, and the last gets the quantity of a given ingredient type. I want to call all three consecutively passing the previous information along to the next call so that the returned responses can be mapped to the same initial list of recipes. Essentially each consecutive call would add to the previously returned info and the list of objects would grow in complexity with each successive call. I also need to apply a custom mapping to each return. I also need them to resolve at the same time so I can simply subscribe to the end result. I know I'll probably need to use switchMap or concatMap but I'm unsure of how to structure this.
Any help would be appreciated
Examples of my service calls and their mappings
Get recipes
let allRecipes: Observable<RecipeModel[]> = this.recipeListService.GetRecipesFromAirtable(
allTypes, allOccassions, allPrepStyles, allFamilies, muddlingReq,
allPrimaryComponents, allSecondaryComponents, recipeName
).pipe(map(response => {
let allRecipes: RecipeModel[] = response.records.map(
recipeObj => {
//console.log(recipeObj.fields);
let model: RecipeModel = {
id: recipeObj.fields["Recipe ID"],
name: recipeObj.fields["Name"],
variant: '',
version: 0,
type: recipeObj.fields["Type"]
}
let variant: string = recipeObj.fields["Variant"];
if(variant !== null && variant !== undefined) {
model.variant = variant;
}
let version: number = recipeObj.fields["Version"];
if(version !== null && version !== undefined && isNaN(version) !== true) {
model.version = version;
}
return model;
}
)
return allRecipes;
}));
Get Ingredients
let allIngredients: Observable<IngredientModel[]> = this.ingredientService.GetIngredientsFromAirtable(recipe.id)
.pipe(
map(response => {
let allIngredientObjs: IngredientModel[] = response.records.map(
ingredientObj => {
let model: IngredientModel = {
order: ingredientObj.fields["Order"],
name: ingredientObj.fields["Ingredient Name"][0],
qualifier: ingredientObj.fields["Qualifier"],
optional: ingredientObj.fields["Optional"] ? ingredientObj.fields["Optional"] : false,
amountReq: { },
notes: ingredientObj.fields["Notes"]
}
let allFields: [string, string][] = [["Cups", "cup"], ["Ounces", "oz"], ["Millilitres", "mL"], ["Quantity", ""], ["Grams", "g"],
["Dashes", ""], ["Barspoons", "barspoons"], ["Teaspoons", "tsp"], ["Misc", ""]];
for(let i = 0; i < allFields.length; i++) {
let fieldName: string = allFields[i][0];
let value: string = ingredientObj.fields[fieldName];
if(value === null || value === undefined || value.length == 0) {
continue;
}
model.amountReq[fieldName.toLowerCase()] = {units: allFields[i][1], amount: value};
}
// Add type info
model.type = {
superType: ingredientObj.fields["Ingredient Supertype"],
type: ingredientObj.fields["Ingredient Type"],
subType: ingredientObj.fields["Ingredient Subtype"]
}
return model;
}
)
return allIngredientObjs;
}));
Get Ingredient Quantity
let ingredientQuantity: Observable<number> = this.inventoryService.GetIngredientQuantitiesFromAirtable(
inventoryName, ingredientName)
.pipe(
map(response => {
let quantity = 0;
let allLiquorObjs = response.records.map(
liquorObj => {
let model = {
brand: liquorObj.fields["Brand"][0],
desc: liquorObj.fields["Description"][0],
volume: liquorObj.fields["Current Volume (mL)"]
}
if("specialValue" in model.volume) {
model.volume = -1;
}
if(model.volume > 0) {
quantity += model.volume;
}
// return model;
}
)
return quantity;
}));
So far I have the following worked out thanks to Elias Dal Ben's help
let allRecipes: Observable<RecipeModel[]> = this.getAllRecipesObservable(this.allDrinkTypes,
this.allDrinkOccassions, this.allPreparationStyles, this.allFamilies, this.muddlingRequired,
this.allPrimaryComponents, this.allSecondaryComponents, this.recipeNameToFind)
.pipe(
tap(allRecipes => {
console.debug('Recipes(' + allRecipes + ')');
}),
concatMap(data => {
let allRecipes = data;
allRecipes.map(
recipe => {
let allIngredients: Observable<IngredientModel[]> = this.getAllIngredientsObservable(recipe);
allIngredients.pipe(
tap(allIngredients => {
console.debug('Ingredients(' + allIngredients + ')');
}),
concatMap(data => {
let allIngredients = data;
allIngredients.map(
ingredient => {
let quantity: Observable<number> =
this.getIngredientQuantityObservable(this.inventoryAddr, ingredient.type.name);
quantity.pipe(
tap(quantity => {
console.debug('Quantity(' + quantity + ')');
})
)
return quantity;
}
)
})
)
return allIngredients;
}
)
return allRecipes;
})
)
However on the first line allRecipes gives me an error of
"Type 'Observable' is not assignable to type 'Observable<RecipeModel[]>'"
and data in the second concatMap gives me an error of
"Argument of type '(data: IngredientModel[]) => void' is not assignable to parameter of type '(value: IngredientModel[], index: number) => ObservableInput'. Type 'void' is not assignable to type 'ObservableInput'."
Does anyone know what I'm missing?