RxJS 6 фильтрует и отображает наблюдаемый массив элементов - PullRequest
0 голосов
/ 07 декабря 2018

В моем приложении Angular 7.1.1 с RxJS 6.3.3 наблюдаемый массив планов должен быть преобразован в наблюдаемый массив карт активных планов.Активный фильтр:

filter(plan => plan.is_active)

и преобразование плана в карточку:

map(plan => new PlanCard(plan, 1, 1))

поэтому, предположительно, ответ будет примерно таким:

plans: Observable<Plan[]> = getPlans();

cards: Observable<PlanCard[]> = plans.pipe(
  mergeAll(),
  filter(plan => plan.is_active),
  map(plan => new PlanCard(plan, 1, 1)),
  toArray()
);

Но увы, cards пусто.

Планы можно корректно преобразовать в карты с помощью:

cards: Observable<PlanCard[]> = plans.pipe(
  map(plans => plans.map(plan => new PlanCard(plan, 1, 1)))
);

, но добавление предварительного фильтра не приводит к фильтрации планов, к сожалению:

cards: Observable<PlanCard[]> = plans.pipe(
  filter(plans => plans.filter(plan => plan.is_active)),
  map(plans => plans.map(plan => new PlanCard(plan, 1, 1)))
);

Любые лучшие идеи?

export const planData: Plan[] = [{
  name: 'P1',
  is_active: true
}, {
  name: 'P2',
  is_active: true
}, {
  name: 'P3',
  is_active: true
}, {
  name: 'P4',
  is_active: true
}, {
  name: 'P5',
  is_active: false
}];

export const plans = createObservable(planData);

Ответы [ 2 ]

0 голосов
/ 18 апреля 2019

Это заставило меня немного почесать голову, так что краткий пример, который может быть полезен, если вы хотите отфильтровать наблюдаемый массив объектов.Слава @ Адриану за указание мне в правильном направлении.

Если у вас есть служба, которая возвращает наблюдаемый массив объектов, например:

dataSub = new BehaviorSubject<Array<object>>([]);

getItems(): Observable<Array<object>>  {
    return this.dataSub.asObservable();
}

Вы можетефильтр с заданными критериями со следующим.В этом примере я хочу использовать только те элементы, для которых свойство 'selected' имеет значение true.

constructor() {
  this.getItems()
    .pipe(
      map(items => items.     /* Don't forget this! */
      filter(item => item['selected'] === true))
    )
    .subscribe(data => {
      console.log(data);
    });
}

Ошибка (новобранец), которая привела к моей путанице, заключалась в пропуске карты, поэтому применялась функция фильтра.на весь массив, а не на каждый элемент.

0 голосов
/ 07 декабря 2018

mergeAll объединяет наблюдаемую из наблюдаемых.

Вы хотите

cards: Observable<PlanCard[]> = plans.pipe(
  map(plans => plans.filter(plan => plan.is_active)), // An array comes down the pipe, you don't want to filter out the arrays but the elements in the array
  map(plans => plans.map(plan => new PlanCard(plan, 1, 1))), // An array of active plans can be mapped into an array of PlanCards
  reduce((results, plans) => [...results, ...plans], []) // Reduce all the arrays into a single array
);

Вы можете использовать сканирование вместо уменьшения, если вы хотите, чтобы аккумулятор сокращения уменьшался по трубе каждый раз, когдановый массив рушится, уменьшайте только пожары после того, как все массивы спустятся по трубе.

Обычно я не использую фильтр, за которым следует карта, но легче увидеть, что происходит, я обычно делал быэто за один шаг с уменьшением,

plans => plans.reduce((results, plan) => plan.is_active ? [...results, new PlanCard(plan, 1, 1)] : results, [])

То же, что фильтр, за которым следует карта, но делает это за одну итерацию вместо двух.

Это может быть довольно запутаннымкогда у вас есть наблюдаемые массивы, вам нужно подумать, какие функции вы хотите применить к наблюдаемой, а какие - к массиву, который идет по трубе.

const { from } = rxjs;
const { map, reduce } = rxjs.operators;

const plans = from([
  [{id: 1, is_active: true}, {id: 2, is_active: false}, {id: 3, is_active: true}, {id: 4, is_active: true}],
  [{id: 5, is_active: true}, {id: 6, is_active: true}],
  [{id: 7, is_active: false}, {id: 8, is_active: true}, {id: 9, is_active: true}],
  [{id: 10, is_active: true}, {id: 11, is_active: false}, {id: 12, is_active: true}, {id: 13, is_active: false}],
]);

function PlanCard(plan) {
  this.id = plan.id;
}

plans.pipe(
  map(plans => plans.reduce((results, plan) => plan.is_active ? [...results, new PlanCard(plan, 1, 1)] : results, [])),
  reduce((results, plans) => [...results, ...plans], [])
).subscribe(results => { console.log(results); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.3.3/rxjs.umd.min.js"></script>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...