разбиение на страницы с помощью Clarity vmware с помощью пагинатора firestore не работает при использовании .ограничение

# #angular #typescript #google-cloud-firestore #pagination #vmware-clarity

Вопрос:

У меня есть сетка данных с пагинатором и возможностью выбора нужного пользователю размера страницы. Мои данные находятся в Google Firestore. Мне нужно ограничить данные на стороне сервера, так как база данных будет большой, и это повлияет на производительность. Но когда я ограничиваю данные, пейджинатор имеет доступ только к первым 25 записям, что означает, что пользователь не видит стрелок вперед или назад, которые позволили бы ему перейти на следующую страницу. Я работаю над этим уже несколько дней и не могу найти ответ. Поскольку мои данные из firestore, было бы слишком много времени, чтобы создать stackblitz и изменить все функции для работы с локальными данными. Есть идеи, что я делаю не так? Я думал, что моя проблема заключалась в том, что не хватало общего количества элементов, поэтому я создал функцию getLength (), чтобы справиться с этим, но это не меняет поведения. То, что я вижу внизу страницы, заключается в следующем: введите описание изображения здесьвместо этого введите описание изображения здесьэто мой компонент

 import {ChangeDetectionStrategy, Component, OnInit} from '@angular/core';
import {AngularFirestore} from '@angular/fire/firestore';
import {BehaviorSubject, combineLatest, Observable, Subject} from 'rxjs';
import {distinctUntilChanged, map, switchMap, tap} from 'rxjs/operators';
import {Caregiver, CaregiverState, Paginator} from '../caregiver.interface';
import {environment} from '../../../environments/environment';
import {AgencyObj} from '../../agencies/agencies/Agency.interface';
import {ClrDatagridFilterInterface, ClrDatagridStateInterface} from '@clr/angular';
import {ExportCsvService} from 'src/app/shared/services/export-csv.service';
import {DateRangeFilter} from "../../transactions/transactions/transactions.component";
import {Transaction} from "../../transactions/transactions/Transaction.interface";
import firebase from "firebase";
import Timestamp = firebase.firestore.Timestamp;


let STATE: CaregiverState = {
  caregivers: [],
  filters: [],
  pagination: {
    after: undefined,
    before: undefined,
    page: 1,
    rows: 25,
    limit: 25
  },

};

@Component({
  selector: 'app-caregivers',
  templateUrl: './caregivers.component.html',
  styleUrls: ['./caregivers.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CaregiversComponent implements OnInit {
  store = new BehaviorSubject(STATE);
  public state$ = this.store.asObservable();
  api_root = environment.API_ROOT;
  agencyObj = AgencyObj;
  onBoardingCompletedFilter: OnBoardingCompletedFilter;
  nameFilter: NameFilter;
  nameFilterValues = ['xxx', 'yyy', 'zzz']
  phoneFilter: PhoneFilter;
  caregiverCodeFilter: PhoneFilter;
  dateCreatedFilter: DateRangeFilter
  agencyName: string;
  agencyId: string;
  rows = 25;
  caregiverLength: number;

  pagination$ = this.state$.pipe(
    map((state) => state.pagination),
    distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))
  );
  filters$ = this.state$.pipe(
    map((state) => state.filters),
    distinctUntilChanged()
  );


  caregivers$: Observable<Caregiver[]> = combineLatest([this.pagination$, this.filters$]).pipe(
    switchMap(([pagination, filters]) => {
      return this.afs
        .collection<Caregiver>('caregivers', (ref) => {
          let query: any = ref;

          if (filters?.length) {
            for (const filter of filters) {
              if (filter.property === "onboardingCompleted") {
                const value = JSON.parse(filter.value?.toString());
                query = query.where(filter.property, "==", value)
              }
              if (filter.property === 'agency.agencyId') {
                query = query.where(filter.property, 'in', filter.value)

              }
              if (filter.property === 'phoneNumbers') {
                console.log(filter.property);
                query = query.where(filter.property, 'array-contains', filter.value)
              }
              if (filter.property === 'caregiverCode' amp;amp; filter.value) {
                console.log(filter.property);
                query = query.where(filter.property, '==',  filter.value)
              }

              if (filter.property === 'createdAt') {
                if (filter.value) {
                  const fromDate = new Date(filter.value.replace(/-/g, '/'));
                  console.log(fromDate);
                  query = query.where(
                    filter.property,
                    filter.operator,
                    fromDate
                  );
                }
                if (filter.value2) {
                  const toDate = new Date(filter.value2.replace(/-/g, '/'));
                  toDate.setDate(toDate.getDate()   1);
                  console.log(toDate);
                  query = query.where(
                    filter.property,
                    filter.operator2,
                    toDate
                  );
                }
              }
            }
          }

          if (pagination.after) {
            const state = this.store.getValue();
            const pagination: Paginator = {
              after: state.caregivers[state.caregivers.length - 1],
              before: undefined,
              limit: state.pagination.limit,
            }
            if (this.dateCreatedFilter.value !== null) {
              query = query
                .orderBy('createdAt', 'asc')
                .orderBy('firstName', 'asc')
                .orderBy('caregiverId')
                .startAfter(pagination.after.firstName,
                  pagination.after.caregiverId)

            } else {
              query = query
                .orderBy('firstName', 'asc')
                .orderBy('caregiverId')
                .startAfter(
                  pagination.after.firstName,
                  pagination.after.caregiverId
                )

            }
          } else if (pagination.before) {
            const state = this.store.getValue();
            const pagination: Paginator = {
              after: undefined,
              before: state.caregivers[0],
              limit: state.pagination.limit,
            }
            if (this.dateCreatedFilter.value !== null) {
              query = query
                .orderBy('createdAt', 'asc')
                .orderBy('firstName', 'asc')
                .orderBy('caregiverId')
                .endBefore(
                  pagination.before.firstName,
                  pagination.before.caregiverId,
                )
            } else {
              query = query
                .orderBy('firstName', 'asc')
                .orderBy('caregiverId')
                .endBefore(
                  pagination.before.firstName,
                  pagination.before.caregiverId,
                )
            }
          } else {
            let pagination = this.store.getValue().pagination;
            if (this.dateCreatedFilter.value !== null) {
              query = query.orderBy('createdAt', 'asc')
                .orderBy('firstName', 'asc')
                .limit(pagination.limit)

            } else {
              query = query.orderBy('firstName', 'asc')
                .limit(pagination.limit)

            }
          }
          // this.updateState({...STATE, pagination})

          return query;

        })
        .valueChanges()
        .pipe(
          tap(console.log),
          tap((caregiversArray) => {
            const caregivers = caregiversArray;
            this.updateState({...STATE, caregivers});
          })
        );
    })
  );


  constructor(public afs: AngularFirestore, private csvExport: ExportCsvService) {
    this.onBoardingCompletedFilter = new OnBoardingCompletedFilter();

  }


  ngOnInit(): void {
    this.nameFilter = new NameFilter();
    this.nameFilter.value = [];
    this.phoneFilter = new PhoneFilter();
    this.phoneFilter.value = '';
    this.caregiverCodeFilter = new PhoneFilter();
    this.caregiverCodeFilter.property = 'caregiverCode';
    this.dateCreatedFilter = new DateRangeFilter();
    this.dateCreatedFilter.value = null;
    this.dateCreatedFilter.value2 = null;
    this.dateCreatedFilter.property = 'createdAt';
    this.dateCreatedFilter.operator = '>=';
    this.dateCreatedFilter.operator2 = '<=';
    this.getLength();
  }

  resetDateRangeFilter() {
    this.dateCreatedFilter.value = null;
    this.dateCreatedFilter.value2 = null;
    this.dateCreatedFilter.changes.next(null);

  }

  updateNameFilter(event) {
    if (event.target.checked) {

      if (this.nameFilter.value.indexOf(event.target.value) == -1) {
        this.nameFilter.value.push(event.target.value);
      }
    } else {
      const findFilterIndex = this.nameFilter.value.indexOf((event.target.value));
      this.nameFilter.value.splice(findFilterIndex, 1);
    }
    let filters = this.store.getValue()?.filters;
    if (!filters?.length) filters = [];
    const nameFilterIndex = filters.findIndex(f => f.property === this.nameFilter.property);
    if (nameFilterIndex !== -1) filters[nameFilterIndex] = this.nameFilter;
    else filters.push({value: this.nameFilter.value, property: this.nameFilter.property});

    this.updateState({...STATE, filters})
    this.nameFilter.changes.next(true);
  }

  updatePhoneFilter(event) {
    this.phoneFilter.value = event.target.value?.replace(/[^d]/g, '')
    let filters = this.store.getValue()?.filters;
    if (!filters?.length) filters = [];

    filters.push({
      value: this.phoneFilter.value,
      property: this.phoneFilter.property
    })
    this.updateState({...STATE, filters})
    this.nameFilter.changes.next(true);
  }

  updateCaregiverCodeFilter(event) {
    this.caregiverCodeFilter.value = event.target.value
    let filters = this.store.getValue()?.filters;
    if (!filters?.length) filters = [];
    filters.push({
      value:  this.caregiverCodeFilter.value,
      property: this.caregiverCodeFilter.property
    })
    this.updateState({...STATE, filters})
    this.nameFilter.changes.next(true);

  }

  updateDateFilter(event, direction) {
    if (direction === 'from')
      this.dateCreatedFilter.value = event.target.value;
    if (direction === 'to')
      this.dateCreatedFilter.value2 = event.target.value;
    let filters = this.store.getValue()?.filters;
    if (!filters?.length) filters = [];
    const dateRangeFilterindex = filters.findIndex(
      (f) => f.property === this.dateCreatedFilter.property
    );
    if (dateRangeFilterindex !== -1)
      filters[dateRangeFilterindex] = this.dateCreatedFilter;
    else
      filters.push({
        value: this.dateCreatedFilter.value,
        value2: this.dateCreatedFilter.value2,
        property: this.dateCreatedFilter.property,
      });
    this.updateState({...STATE, filters});
  }

  toggleOnboardingCompletedSelection(event: any): void {
    if (event.target.value === 'undefined')
      this.onBoardingCompletedFilter.value = 'true';
    else
      this.onBoardingCompletedFilter.value =
        event.target.value === 'true' ? 'false' : 'true';

    this.onBoardingCompletedFilter.changes.next(
      this.onBoardingCompletedFilter.value
    );
  }

  resetToggleOnboardingCompletedSelection() {
    this.onBoardingCompletedFilter.value = 'undefined';
    this.onBoardingCompletedFilter.changes.next('undefined');
  }

  onTableRefresh(state: ClrDatagridStateInterface<Caregiver>): void {
    console.log(state);
    this.updateState({...STATE, filters: state.filters})
  }

  private updateState(state: CaregiverState): void {
    this.store.next((STATE = state));
  }

  async downloadCsv() {
    const dataSnapshots = await this.afs.collection<Caregiver>('caregivers').get().toPromise();
    const data = [];
    for (const snapsot of dataSnapshots.docs) {
      data.push(snapsot.data())
    }
    const header = ['caregiverId', 'firstName', 'lastName', 'agency.name', 'createdAt', 'caregiverCode', 'phoneNumbers'];
    const filename = 'caregivers';
    this.csvExport.downloadCsv(data, header, filename);
  }

  async getLength() {
    const dataSnapshots = await this.afs.collection<Caregiver>('caregivers').get().toPromise();
    this.caregiverLength = dataSnapshots.docs.length;
    console.log(this.caregiverLength);

  }


}


export class OnBoardingCompletedFilter implements ClrDatagridFilterInterface<Caregiver> {
  changes = new Subject<any>();
  value = "undefined";
  property = 'onboardingCompleted';

  isActive(): boolean {
    return this.value !== "undefined";
  }

  accepts(caregiver: Caregiver) {
    return this.value !== "undefined" amp;amp; JSON.parse(this.value) === caregiver.onboardingCompleted;
  }
}

export class NameFilter implements ClrDatagridFilterInterface<Caregiver> {
  changes = new Subject<any>();
  value = [''];
  property = 'agency.agencyId';

  isActive(): boolean {
    return this.value.length > 0;

  }

  accepts(caregiver: Caregiver) {
    return true;
  }
}

export class PhoneFilter implements ClrDatagridFilterInterface<any> {
  changes = new Subject<any>();
  value = '';
  property = 'phoneNumbers';

  isActive(): boolean {
    return this.value !== '';

  }

  accepts(any) {
    return true

  }
}


export class CreatedDateFilter implements ClrDatagridFilterInterface<Transaction> {
  changes = new Subject<any>();
  value: Timestamp | string;
  value2: Timestamp | string;
  property = '';
  operator = '>=';
  operator2 = '<=';

  isActive(): boolean {
    return this.value !== null   amp;amp; this.value2 !== null;
  }

  accepts(transaction: Transaction) {
    return true;
  }
}
 

и мой шаблон

 <clr-dg-footer>
      <div class="clr-row clr-justify-content-between">

        <cds-icon class="btn-icon" style="margin: 5px 0 0 30px; cursor: pointer;" shape="xls-file" size="md"
                  status="success" (click)="downloadCsv()"></cds-icon>
        <div>
          <clr-dg-pagination
            #pagination
            [clrDgPageSize]="rows"
            [clrDgTotalItems] = pagination.totalItems>

            <clr-dg-page-size [clrPageSizeOptions]="[25, 50, 100, 500, 1000]"
            >records per page
            </clr-dg-page-size>
            {{ pagination.firstItem   1 }} - {{ pagination.lastItem   1 }} of
            {{pagination.totalItems }} records
          </clr-dg-pagination>
        </div>
      </div>
    </clr-dg-footer>
 

если я изменю свой html следующим образом:{{ разбиение на страницы.firstItem 1 }} — {{ разбиение на страницы.Последнее число 1 }}
записей {{Продолжительность ухода }}
Я получаю правильное количество записей вместо 25, но я не получаю стрелок, которые нужны пользователю для перехода на следующую или pr-страницу. Когда я отлаживаю, я вижу, что totalItems, которая является встроенной переменной пагинатора, изменяется с правильной длины массива на 25, что является значением строк.

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

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