Ваша проблема
Вы не возвращаете наблюдаемую combineLatest
в switchMap
.
Внутри блока if
в switchMap
, вы просто создаете неиспользованный карта наблюдаемых.
Очень упрощенно, вы сейчас делаете это:
switchMap(response =>
if (response["logs"]) {
response["logs"].map(logs => of(logs));
}
return of(response);
}
Я упростил ваш последний комбайн до of
, чтобы продемонстрировать проблему. Когда условие if
выполнено, блок создаст новый массив, который затем немедленно игнорируется. Это означает, что независимо от вашего условия if, switchMap
всегда будет вызывать of(response)
. Ваш массив combineLatest
не будет работать никогда .
Решение
Вам необходимо вернуть какое-то наблюдаемое из вашего блока if
. Если вы думаете о типе данных, который вы создаете, это массив наблюдаемых. Поэтому для этого вам понадобится forkJoin
для запуска массива наблюдаемых и возврата одной наблюдаемой, на которую switchMap
может переключиться.
return this.API.getPost(this.route.params.id).pipe(
switchMap((response: any) => {
if (response["logs"]) {
return forkJoin(response["logs"].map(logs => {
if (logs["files"]) {
return combineLatest(
...logs["files"].map(file=>
this.API.getFile(file.id)
)
).pipe(
map(files =>
files.map(file => ({
url: this.sanitizer.bypassSecurityTrustResourceUrl(
window.URL.createObjectURL(file)
)
}))
)
),
// Not sure what this is???
map(files => {
logs["files"] = files;
return response;
});
}
}));
}
return of(response);
})
)
Кроме того, я не уверен, какова цель map
это то, что я прокомментировал - в настоящее время он не имеет смысла, и это может даже вызвать проблемы компиляции.
DEMO: https://stackblitz.com/edit/angular-5jgk9z
Это демо упрощенная c абстракция вашей проблемы. «Не работающая» версия создает карту наблюдаемых, которые она не возвращает. «Рабочая» версия переключается на forkJoin
и возвращает это. В обоих случаях условие защиты блока if
выполняется.
Оптимизация наблюдаемого создания
Я думаю, что создание внутренних наблюдаемых можно упростить и сделать более безопасным.
Кажется немного избыточным заключать массив combineLatest
в forkJoin
, когда вы можете просто использовать forkJoin
напрямую.
И чтобы сделать его более понятным, я бы отделил отображение массива от наблюдаемое создание. Это также поможет вам избежать ошибок, когда вы получите пустой массив, идущий в combineLatest
или forkJoin
.
// inside the "if" block
// flatten files
const files = response["logs"]
.filter(log => !!log.files)
.map(log => log.files)
.flat();
if (files.length > 0) {
const observables = files.map(file => this.API.getFile(file.id));
return forkJoin(observables).pipe(
map(files => {
files.map(file => ({
url: this.sanitizer.bypassSecurityTrustResourceUrl(
window.URL.createObjectURL(file)
)
}))
})
);
}
При этом используется функция массива .flat()
, которая принимает многомерный массив, такой как :
[
[1,2,3],
[4,5,6]
]
и сводит это к следующему:
[ 1,2,3,4,5,6 ]
Если вам нужна поддержка IE и у вас нет polyfill, вы можете использовать альтернативу здесь: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat.
Я также рекомендовал бы создать некоторые интерфейсы и использовать строгую типизацию. Вы скоро заблудитесь, если будете полагаться исключительно на правильное именование переменных (разумеется, мы не даем переменным плохие имена ...)