Изменение одного наблюдаемого на основе другого

#angular #rxjs

Вопрос:

Я работаю над приложением, в котором есть раздел «Избранное». Я извлекаю два источника данных: один из файла const, который я экспортирую как наблюдатель(observerA$), и один из базы данных, которая содержит только идентификаторы, которые были выбраны(observerB$), и оба работают по назначению. Я хотел бы использовать сохраненные идентификаторы из observerB$, чтобы пометить логическое значение в observerA$

ObserverA$ содержит всю информацию, которую я использую для заполнения пользовательского интерфейса. Интерфейс для observerA

 {
    title: string,
    id: number,
    page: string,
    subcategory: string,
    favorite?: boolean
}
 

observerB$ содержит идентификаторы для избранных элементов
Интерфейс для наблюдателя$

 {
   (some unrelated fields)
   id: number
}
 

Я заставляю его работать, изменяя массив внутри моего компонента, но так как он используется в нескольких компонентах, я бы подписался на observerA$, используя asyncpipe, чтобы получать обновления без необходимости использовать массив машинописи

Комментарии:

1. Можете ли вы создать Стакблитц ?

2. Нам понадобится немного больше, чтобы продолжить, потому что то, как вы работаете с двумя массивами, зависит от особенностей того, чего вы пытаетесь достичь. Если вам нужны некоторые общие идеи работы с декларативным подходом, ознакомьтесь с первыми 30 минутами этого видео: youtube.com/watch?v=iSsch65n8Yw

3. Если ObserverA$ содержит всю информацию, которую я использую для заполнения пользовательского интерфейса, то, похоже, вы показываете только один заголовок? Это правда?

4. Да, и извините за недостаток информации, я новичок в angular после работы в knockoutjs в течение последних 3 лет, поэтому я не уверен во всей терминологии. По сути, ObserverA$ содержит всю необходимую информацию для пользовательского интерфейса. Я хочу подписаться на этого наблюдателя, чтобы заполнить пользовательский интерфейс, но мне нужно изменить логическое значение «избранное», сопоставив идентификаторы из observerB$. Я рассмотрю возможность использования stackblitz для получения дополнительной информации. В настоящее время я пытаюсь использовать .map для достижения этой цели

Ответ №1:

Это звучит так, как будто вы пытаетесь составить наблюдаемое из двух наблюдаемых источников. Давайте назовем ваши два источника наблюдаемыми item$ и favoriteIds$ для простоты.

Вы можете определить свою составленную наблюдаемую (назовите ее itemWithFavoriteProperty$ просто для краткости) следующим образом:

 const itemWithFavoriteProperty$ = item$.pipe(
  switchMap(item => favoriteIds$.pipe(
    map(favoriteIds => favoriteIds.some(id => id === item.id)),
    map(favorite => ({...item, favorite}))
  ))
);
 

Если вы не знакомы с switchMap ним , он в основном подписывается на наблюдаемый источник и испускает свои выбросы. Таким образом, всякий item$ раз, когда эмиссирует, switchMap будет подписываться favoriteIds$ и выдавать массив идентификаторов (в любое время, когда он меняется), который мы затем сопоставляем:

  • сначала к логическому значению, указывающему, находится ли элемент в избранном массиве
  • затем к копии, выданной item с приложением favorite свойства.

Так itemWithFavoriteProperty$ будет излучать в любое время item$ или когда favoriteIds$ будет излучать. Однако на самом деле мы не хотим выдавать, если favorite логическое значение не изменилось, поэтому мы можем использовать distinctUntilChanged :

 const itemWithFavoriteProperty$ = item$.pipe(
  switchMap(item => favoriteIds$.pipe(
    map(favoriteIds => favoriteIds.some(id => id === item.id)),
    distinctUntilChanged(),
    map(favorite => ({...item, favorite}))
  ))
);
 

Вот стекблитц, с которым вы можете поиграть.

Комментарии:

1. Большое вам спасибо за помощь. Похоже, это правильное направление для меня, я действительно ценю это. Единственная проблема, с которой я сталкиваюсь прямо сейчас, заключается в том, что я получаю ошибку после .some, в ней говорится, что идентификатор не существует в элементе [], поэтому я думаю, что мне нужно распаковать этот массив, прежде чем он заработает, но это огромная помощь