Фильтровать список по категориям — Angular 8

У меня есть список из firebase, который я хочу отфильтровать и отобразить по специализациям в каждой категории. Когда я делаю консольный журнал, извлекаются как категории, так и специализации, но я не могу понять, что мне нужно сделать, чтобы отобразить специализацию в пользовательском интерфейсе, когда выбрана категория. Любое руководство будет оценено. Спасибо. Ниже моя работа:

Вывод проекта

Дизайн коллекции баз данных

категория.JSON

{ "-Lq2PAU_P-fPniAMrQ85": { "name" : "test" }, "accountingFinance" : { "name" : "Бухгалтерский учет и финансы" }, "assuranceAudit" : { "name" : "Assurance and Audit" }, "управление рисками" : { "название" : "Управление рисками" }, "налогообложение" : { "название" : "Налогообложение" } }

категории.JSON

{
  "accountingFinance" : [ null, "Accounting Management Information Systems", "Accounting Records Maintenance", "Accounts Preparation", "Accountancy / Finance Training" ],
  "assuranceAudit" : [ null, "Asset Management Review", "Assurance / Audit Training", "Climate Change / Sustainability Audit", "Enviromental Audit" ],
  "riskManagement" : [ null, "Acturial Service", "Enterprise Risk Management", "Fraud Risk Management", "Political Risk Management" ],
  "taxation" : [ null, "Business Income Tax", "Capital Gains Tax", "Corporation Tax", "Employee Tax (PAYE)", "Export Incentives" ]
}

HTML-разметка

<div class="row">
                            <div class="col-4">
                                <div class="list-group">
                                    <a 
                                        *ngFor="let c of (category$ | async)" 
                                        routerLink="/admin/expert-category" [queryParams]="{ category: c.key }"
                                        class="list-group-item list-group-item-action"
                                        [class.active]="category === c.key">
                                        {{ c.name }}
                                    </a>
                                </div>
                            </div>
                            <div class="col">
                                <div class="row">
                                    <ng-container *ngFor="let categories of filteredCategories; let i = index">
                                        <div class="col">
                                            <div class="card">
                                                <!--<div class="card-body">-->
                                                    <ul class="list-group list-group-horizontal">
                                                        <li class="list-group-item">{{ categories }}</li>
                                                    </ul>
                                                <!--/div>-->
                                            </div>
                                        </div>
                                        <div  *ngIf="(i+1) % 4 === 0" class="-w-100"></div>
                                    </ng-container>     
                                </div>
                            </div>
                        </div>

Сервис.тс

getCategories(): Observable<any[]> {
    return this.db.list('/categories')
    .snapshotChanges().pipe(
      map(actions =>
        actions.map(data => ({ key: data.key, ...data.payload.val() }))
    ));
  }

  getAll(): Observable<any[]> {
    return this.db.list('/category')
    .snapshotChanges().pipe(
      map(category =>
        category.map(cat => {
            const key = cat.key;
            const payload = cat.payload.val();
            return { key, ...payload };
          })),
        );
  }

Файл Component.ts

export class ExpertCategoryComponent implements OnInit {
  category$;
  category: string;
  closeResult: string;
  filteredCategories: any[] = [];
  specialization: any[] = [];

  constructor(
    private categoryService: CategoryService,
    route: ActivatedRoute,
    private router: Router,
    private modalService: NgbModal) {

      this.categoryService.getCategories().subscribe(specialization => {
        this.specialization = specialization;
        console.log(this.specialization);
        route.queryParamMap.subscribe(params => {
          this.category = params.get('category');

          this.filteredCategories = (this.category) ? this.specialization.filter(s => s.category === this.category) : this.specialization;
          console.log(this.filteredCategories);
          });
      });

      this.category$ = this.categoryService.getAll();
  }

На данный момент я не получаю никаких ошибок, кроме пустого массива в консоли, когда я выбираю категорию.


person E. Ogony    schedule 04.10.2019    source источник
comment
Лучший способ - использовать пользовательский канал для фильтрации чего-либо.   -  person Mises    schedule 04.10.2019
comment
@Mises Не согласно их документации: angular.io/guide/pipes# приложение-без-filterpipe-или-orderbypipe   -  person peinearydevelopment    schedule 04.10.2019
comment
Я не вижу category в вашем примере JSON, но вы используете его в (s.category)   -  person Maihan Nijat    schedule 04.10.2019
comment
bitbucket.org/ mises543/sorting-list/src/master/src/app/shared/ этот канал сортируется по категории/запросу/сортировке в алфавитном порядке по названию и времени.   -  person Mises    schedule 04.10.2019
comment
@peinearydevelopment Пользовательская труба не является универсальной.   -  person Mises    schedule 04.10.2019
comment
@peinearydevelopment Работа видишь? sorting-list-angular.web.app/library   -  person Mises    schedule 04.10.2019
comment
СКОЛЬКО элементов мы ожидаем через этот звонок?   -  person Saksham    schedule 04.10.2019
comment
На самом деле я реализую то, что узнал из учебника, в своем собственном проекте. Я новичок в этом, так что будьте любезны со мной, если я медленный. Это мой второй пример JSON для s.category.   -  person E. Ogony    schedule 04.10.2019
comment
{ -Lq2PAU_P-fPniAMrQ85 : {название : тест }, бухгалтерский учет и финансы : {название : Бухгалтерский учет и финансы }, обеспечение аудита : {название : Гарантия и аудит }, Управление рисками : {название : Управление рисками }, налогообложение : {название : Налогообложение } }   -  person E. Ogony    schedule 04.10.2019
comment
Прошу прощения за ужасный формат кода. Как отформатировать код в комментарии?   -  person E. Ogony    schedule 04.10.2019
comment
@peinearydevelopment sorting-list-angular.web.app/library близок к тому, чего я хочу достичь, но я не вижу никакого кода. Не могли бы вы указать мне, где я могу получить его.   -  person E. Ogony    schedule 04.10.2019
comment
На выходных постараюсь добавить немного кода   -  person peinearydevelopment    schedule 04.10.2019
comment
@Maihan Nijat Когда вы упомянули, что (s.category) нет в моем файле JSON, я понял, что у меня проблемы с рендерингом пользовательского интерфейса из-за плохого дизайна базы данных. Я отредактировал свой код, включив в него модель, и попросил вас посмотреть на нее и дать рекомендации. Я еще не нашел никаких решений. Спасибо.   -  person E. Ogony    schedule 06.10.2019
comment
@Mises Я добавил StackBlitz демонстрируя, почему не рекомендуется использовать для этого канал.   -  person peinearydevelopment    schedule 08.10.2019
comment
@peinearydevelopment Полезно знать, но все же моя трубка чистая и срабатывает только при любом изменении sortBy или фильтра. Так что это не испортит пользовательский опыт.   -  person Mises    schedule 08.10.2019
comment
@Mises Это правда, но в документах говорится, что канал должен быть нечистым, потому что он ссылается на свойства объекта. У вас нет, поскольку они жестко запрограммированы в самом канале (например, title, uploaded). Это важно подчеркнуть.   -  person peinearydevelopment    schedule 08.10.2019
comment
@peinearydevelopment Да, я знаю, и есть ли возможность сделать класс окончательным? Как сделать его нерасширяемым?   -  person Mises    schedule 08.10.2019
comment
@peinearydevelopment Потому что кто-то может расширить свою грязную трубу с помощью моей сортировочной трубы.   -  person Mises    schedule 08.10.2019
comment
@Mises См. ошибку GitHub   -  person peinearydevelopment    schedule 08.10.2019
comment
@E.Ogony Если вы пытались применить приведенное ниже к своему коду, и это не сработало, обновите свой вопрос, указав подробности. Еще лучше было бы предоставить свой собственный StackBlitz, чтобы я мог работать с изменениями, которые вам понадобятся, чтобы все заработало.   -  person peinearydevelopment    schedule 08.10.2019
comment
@peinearydevelopment Я ценю вашу заботу. Пожалуйста, найдите ссылку на проект. Если не сложно, не могли бы вы привести пример, в котором используется служба для извлечения данных из базы данных Firebase. stackblitz.com/edit/angular-99tvpd? embed=1&file=src/app/   -  person E. Ogony    schedule 11.10.2019


Ответы (1)


Я создал StackBlitz с кодом.

Есть некоторые незначительные изменения в html, который вы указали выше. Существует также макет «firebase», поэтому вы можете видеть, что я также использую данные, которые вы предоставили выше. Вы, вероятно, захотите посмотреть там полный пример.

Кроме того, многие методы, используемые ниже, взяты у замечательных ораторов, таких как Deborah Kurata и других. .

Что касается вашего вопроса о фильтрации, однако,

import { Component } from '@angular/core';
import { FirebaseStub } from './firebase.stub';
import { Observable, BehaviorSubject, Subject } from 'rxjs';
import { mergeMap, map, tap } from 'rxjs/operators';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular';
  private selectedCategory = new BehaviorSubject<string>('accountingFinance');

  category$: Observable<any>;
  selectedCategory$ = this.selectedCategory.asObservable();
  categories$: Observable<any>;


  constructor(private firebaseStub: FirebaseStub) {
    this.categories$ = this.selectedCategory$
                           .pipe(
                             mergeMap(selectedCategory => this.firebaseStub
                                                              .categories$
                                                              .pipe(map((category: any) => category[selectedCategory]))
                            )
                          );

    this.category$ = firebaseStub.category$
                                 .pipe(
                                   tap((category: any) => this.selectedCategory.next('accountingFinance')),
                                   map(categoryObj => Object.keys(categoryObj).map((key,index) => categoryObj[key].name))
                                  );
  }
}

Я старался придерживаться ваших соглашений об именах, хотя мне немного сложно им следовать. Вы увидите, что categories$ — это отфильтрованный список категорий, основанный на полном списке, полученном от 'firebase', и selectedCategory. В общем, я видел, что значение selectedCategory исходит из раскрывающегося списка в пользовательском интерфейсе, и когда пользователь выбирает новое значение, этот выбор запускает метод для обновления selectedCategory (путем вызова next для него). Я снова жестко закодировал здесь значение, так как это не основная цель вашего вопроса.

Затем фильтрация выполняется с помощью оператора rxjs mergeMap. Он принимает последнее значение, полученное наблюдаемым selectedCategory$, передает его оператору map, который является piped, через наблюдаемое categories$ Firebase. Сопоставленные отфильтрованные категории возвращаются как наблюдаемые categories$ компонента.

ОБНОВЛЕНИЕ

Просто в отношении некоторых комментариев к первоначальному вопросу. Я создал очень маленький/быстрый StackBlitz демонстрирует неэффективность использования нечистого конвейера. Если вы откроете консоль в панели предварительного просмотра, вы увидите, сколько раз нечистый канал вызывается, даже в связи с совершенно не связанными действиями. Каждый раз, когда он вызывается, пользовательский интерфейс перерисовывается.

person peinearydevelopment    schedule 07.10.2019