You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AngularFire2中Firestore无限滚动分页过滤器失效问题求助

It looks like the main issue here is that your filter logic isn’t integrated with the infinite scroll pagination—right now, switching filters replaces your observable with a non-paginated stream, which breaks the infinite scroll behavior. Let’s fix this by combining the filter and pagination logic properly, and also address a potential type mismatch in your filter parameter.

Step 1: Fix the Filter Parameter Mismatch

First, there’s a mismatch between what you’re passing to your filter function and what Firestore expects. You’re sending categoria.nombre (a string) to filtrarData, but the method is typed to accept a Categoria object. If your Firestore documents store the category as a string (the nombre), this comparison will fail. Let’s correct that:

Component.html:

<button *ngFor="let categoria of categoriasTest | async" 
        (click)="filtrarData(categoria.nombre)" 
        class="btn btn-outline-primary btn-sm mx-1">
  {{ categoria.nombre }}
</button>

Component.ts:

filtrarData(categoriaNombre: string) {
  this.selectedCategoria = categoriaNombre; // Store the string value
  this.resetAndLoadFilteredData(categoriaNombre);
}

Step 2: Integrate Filter with Pagination in the Service

We need to modify your service to handle both filtering and pagination. We’ll track the active filter and last loaded document, then build queries that include both.

Service.ts:

import { AngularFirestore, QueryDocumentSnapshot } from '@angular/fire/firestore';
import { Injectable } from '@angular/core';

@Injectable({ providedIn: 'root' })
export class AvisosService {
  private pageSize = 10; // Adjust based on your needs
  private lastDoc: QueryDocumentSnapshot<any> | null = null;
  private activeFilter: string | null = null;

  constructor(private afs: AngularFirestore) {}

  // Set active filter and reset pagination
  setFilter(categoria: string | null) {
    this.activeFilter = categoria;
    this.lastDoc = null; // Reset to load first page of filtered results
  }

  // Load next page of results (with active filter)
  async loadNextPage(): Promise<any[]> {
    let query = this.afs.collection('avisosTest').ref;

    // Apply active filter if present
    if (this.activeFilter) {
      query = query.where('categoria', '==', this.activeFilter);
    }

    // Add orderBy (required for consistent pagination in Firestore)
    // Replace 'createdAt' with your preferred sort field (e.g., 'id')
    query = query.orderBy('createdAt', 'desc').limit(this.pageSize);

    // Add pagination cursor if we have a last document
    if (this.lastDoc) {
      query = query.startAfter(this.lastDoc);
    }

    const snapshot = await query.get();
    
    // Update lastDoc if we have results
    if (snapshot.docs.length > 0) {
      this.lastDoc = snapshot.docs[snapshot.docs.length - 1];
    }

    return snapshot.docs.map(doc => doc.data());
  }
}

Step 3: Update Component to Manage Paginated Results

Your component will now track accumulated results, reset them when filters change, and trigger load more on scroll.

Component.ts:

import { Component } from '@angular/core';
import { AvisosService } from './avisos.service';

@Component({
  selector: 'app-your-component',
  templateUrl: './your-component.html'
})
export class YourComponent {
  filteredAvisos: any[] = [];
  selectedCategoria: string | null = null;
  isLoading = false;

  constructor(private fs: AvisosService) {}

  async resetAndLoadFilteredData(categoriaNombre: string) {
    this.isLoading = true;
    this.fs.setFilter(categoriaNombre);
    this.filteredAvisos = []; // Clear existing results
    const firstPage = await this.fs.loadNextPage();
    this.filteredAvisos.push(...firstPage);
    this.isLoading = false;
  }

  async loadMore() {
    if (this.isLoading) return; // Prevent duplicate requests
    this.isLoading = true;
    const nextPage = await this.fs.loadNextPage();
    this.filteredAvisos.push(...nextPage);
    this.isLoading = false;
  }

  onScroll(event: Event) {
    const container = event.target as HTMLElement;
    // Trigger load more when 100px from the bottom
    if (container.scrollTop + container.clientHeight >= container.scrollHeight - 100) {
      this.loadMore();
    }
  }
}

Component.html:

<!-- Filter buttons -->
<button *ngFor="let categoria of categoriasTest | async" 
        (click)="resetAndLoadFilteredData(categoria.nombre)" 
        class="btn btn-outline-primary btn-sm mx-1"
        [class.active]="selectedCategoria === categoria.nombre">
  {{ categoria.nombre }}
</button>

<!-- Infinite scroll container -->
<div class="avisos-list" (scroll)="onScroll($event)" style="overflow-y: auto; height: 500px;">
  <div *ngFor="let aviso of filteredAvisos" class="aviso-item">
    <!-- Display your aviso data here -->
    <h3>{{ aviso.titulo }}</h3>
    <p>{{ aviso.descripcion }}</p>
  </div>
  <div *ngIf="isLoading" class="text-center">Loading more...</div>
</div>

Key Notes:

  • Firestore Indexes: If you get an error about missing composite indexes, Firestore will provide a link to create the required index automatically (this is needed when combining where and orderBy clauses).
  • Consistent Pagination: Always include an orderBy clause when using startAfter—this ensures Firestore returns consistent pages.
  • Loading State: The isLoading flag prevents multiple simultaneous load requests when the user scrolls quickly.

This approach keeps your filter and pagination logic tightly integrated, so switching filters will reset the pagination and load the first page of the filtered results, while allowing infinite scroll to work with the active filter.

内容的提问来源于stack exchange,提问作者Paco Zevallos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:08:18