Angular - получить массив наблюдаемых из наблюдаемых наблюдаемых - PullRequest
0 голосов
/ 15 октября 2019

Я должен рекурсивно перечислить все сгенерированные observable в одном массиве, чтобы выполнить все это позже.

Для большего контекста, у объекта currentLesson есть список действий. Но activity может быть другим lesson с другими видами деятельности в качестве детей. Я должен (глубоко) загрузить все действия, прежде чем использовать его. Вот почему я пытаюсь использовать рекурсивную функцию.

Это мой код, но в конце сборки возникает ошибка. Я понимаю ошибку, но не знаю, почему data является Observable<Observable<DataEntity>>, а не Observable<DataEntity>[], и я не знаю, как это сделать.

Код:

        const recursivelyGetActivityObservales = (currentLesson: DataEntity): Observable<DataEntity>[] => {
            const obsList: Observable<DataEntity>[] = [];

            const activities: any[] = currentLesson.get('reference');
            for (const activity of activities) {
                if (activity['type'] === 'lesson') {
                    const data = this.getLessonById(activity.id).flatMap(subLesson =>  recursivelyGetActivityObservales(subLesson));
                    obsList.push(...data);
                } else {
                    const loadedActivity = this.activitiesService.getActivityEntity(+activity.id);

                    if (loadedActivity) {
                        obsList.push(from([loadedActivity]));
                    } else {
                        obsList.push(this.activitiesService.loadActivitiesFromId(activity.id));
                    }
                }
            }

            return obsList;
        }

Ошибка:

ERROR in src/app/@modules/activities/core/lessons/lessons.service.ts(321,37): error TS2461: Type 'Observable<Observable<DataEntity>>' is not an array type.

1 Ответ

0 голосов
/ 15 октября 2019

В этой строке:

const data = this.getLessonById(activity.id)
                 .flatMap(subLesson => recursivelyGetActivityObservales(subLesson));

функция recursivelyGetActivityObservales(subLesson) возвращает массив , а не наблюдаемый. Операторы FlatMap / mergeMap должны вернуть наблюдаемую , чтобы работать должным образом.

Я не знаю, что вы будете делать с вашим окончательным массивом наблюдаемых, но если вы ушли в слияниеВ любом случае, быстрое решение - использовать оператор merge(). Пример:

const lessons = (activity) => [
    rxjs.from([1, 2, 3, 4]),
    rxjs.from([1, 2, 3, 4]),
    rxjs.from([1, 2, 3, 4]),
    rxjs.from([1, 2, 3, 4])
]

const activity = rxjs.of('activity1');

const toSub = activity.pipe(rxjs.operators.mergeMap((activity) => rxjs.merge(...lessons(activity))))

toSub.subscribe(console.log)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.js"></script>

В вашем коде:

const data: Observable<DataEntity> = this.getLessonById(activity.id)
             .flatMap(subLesson =>  merge(...recursivelyGetActivityObservales(subLesson)));
obsList.push(data);

Предпочтительное решение:

Сказал, что, IMOправильное решение будет просто возвращать тип Observable<DataEntity>, поскольку оно также представляет несколько объектов DataEntity. В этом случае нет причин иметь массив наблюдаемых.

Для этого я бы просто возвратил объединенный список. Пример:

const recursivelyGetActivityObservales = (currentLesson: DataEntity): Observable<DataEntity> => {
    const obsList: Observable<DataEntity>[] = [];

    const activities: any[] = currentLesson.get('reference');
    for (const activity of activities) {
        if (activity['type'] === 'lesson') {
            const data = this.getLessonById(activity.id).flatMap(subLesson =>  recursivelyGetActivityObservales(subLesson));
            obsList.push(data);
        } else {
            const loadedActivity = this.activitiesService.getActivityEntity(+activity.id);

            if (loadedActivity) {
                obsList.push(from([loadedActivity]));
            } else {
                obsList.push(this.activitiesService.loadActivitiesFromId(activity.id));
            }
        }
    }

    return merge(...obsList);
}

Объяснение:

* Observable<DataEntity> - это структура данных, которая генерирует DataEntities (0, 1 или many ) в течениеи планировщик. Так что на самом деле это контейнер (например, массив) DataEntities. Возьмите этот пример, где обе структуры данных равны одному и тому же результату:

const lessonObsArray =  [ // Observable<DataEntity>[]
    rxjs.of(1),
    rxjs.of(2),
    rxjs.of(3),
    rxjs.of(4),
]

const lessonObs = rxjs.merge( // Observable<DataEntity>
    rxjs.of(1),
    rxjs.of(2),
    rxjs.of(3),
    rxjs.of(4)
);

lessonObsArray.forEach(obs => obs.subscribe(console.log))
console.log('--------')
lessonObs.subscribe(console.log)
// They emit the same!!! (a collection of numbers in this case)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.3/rxjs.umd.js"></script>

Надеюсь, это поможет!

...