Code Monkey home page Code Monkey logo

Comments (5)

google-oss-bot avatar google-oss-bot commented on June 3, 2024

This issue does not seem to follow the issue template. Make sure you provide all the required information.

from angularfire.

Sapython avatar Sapython commented on June 3, 2024

Very little information to deduce the problem. Please upload a part of your project on stackblitz where we can reproduce this issue. Or if possible please share a github repository.

from angularfire.

kshkrao3 avatar kshkrao3 commented on June 3, 2024

@Sapython - The initialization part is very generic which anyone would do normally. It's been shared in the description. Apart from this, I have a lazyLoad service file that would be invoked with the required parameters every time on different components.

Please find the contents of the file below.

//// This Service would be a non singleton instance since it is used by multiple list modules and data has to be fresh for each module
//// Hence, its not provided through Service module, but rather its provided through individual list components
import { Injectable, OnDestroy } from "@angular/core";
import {
  AngularFirestore,
  DocumentSnapshot,
  Query,
} from "@angular/fire/compat/firestore";
import { WhereFilterOp } from "@firebase/firestore-types";
import { Subject } from "rxjs";
import { takeUntil, auditTime, map } from "rxjs/operators";
import * as firebase from "firebase/compat/app";
import { NgxSpinnerService } from "ngx-spinner";
@Injectable({
  providedIn: "root",
})
export class LazyloadService<T> implements OnDestroy {
  tableData: T[] = [];
  where: { key: string; op: WhereFilterOp; value: string | string[] }[] | null =
    [];
  limit = 10;
  collection = "";
  dataLoading = false;
  doneLoading = false;
  spinnerName = "pageLoader";
  // save last document in snapshot of items received
  private lastInResponse: DocumentSnapshot<T> | any;

  // keep the array of first document of previous pages
  private prev_strt_at: DocumentSnapshot<T>[] = [];

  subs$: Subject<void> = new Subject<void>();

  constructor(
    private afs: AngularFirestore,
    private spinnerService: NgxSpinnerService
  ) {}

  loadItems({ isReset = false, isNext = false }) {
    if (isReset) {
      this.dataLoading = false;
      this.doneLoading = false;
      this.tableData = [];
      this.spinnerName = "pageLoader";
    }
    if (this.doneLoading) {
      this.spinnerService.hide("pageLoader");
      this.spinnerService.hide("contentLoader");
    }
    if (this.dataLoading || this.doneLoading) {
      return;
    }
    this.spinnerService.show(this.spinnerName);
    this.dataLoading = true;
    return this.afs
      .collection(this.collection, (ref) => this.createQueryRef(ref, isNext))
      .snapshotChanges()
      .pipe(
        takeUntil(this.subs$),
        auditTime(1000),
        map((response) => {
          this.doneLoading = response.length === 0;
          this.spinnerService.hide(this.spinnerName);
          this.lastInResponse = response[response?.length - 1]?.payload.doc;
          this.push_prev_startAt(this.lastInResponse);
          response.forEach((record) => {
            // Avoid pushing duplicates
            if (
              this.tableData.filter(
                (item: any) => item["id"] === record?.payload.doc.id
              ).length <= 0
            ) {
              this.tableData.push({
                ...(record?.payload.doc.data() as T),
                id: record?.payload.doc.id,
              });
            }
          });
          this.dataLoading = false;
          return;
        })
      );
  }

  private createQueryRef(ref: any, isNext: boolean): Query {
    let queryRef: Query = ref;
    let orderByKey: any = "modifiedDate";
    let order: any = "desc";
    if (this.where) {
      this.where.forEach((condition, index) => {
        const { orderByKeyVal, orderVal, queryRefVal } = this.updateQueryRef(
          condition,
          index,
          orderByKey,
          order,
          queryRef
        );
        queryRef = queryRefVal;
        orderByKey = orderByKeyVal;
        order = orderVal;
      });
    }
    queryRef = queryRef.limit(this.limit);
    if (orderByKey !== "date") {
      queryRef = queryRef.orderBy(orderByKey, order);
    }
    if (isNext && this.lastInResponse) {
      queryRef = queryRef.startAfter(this.lastInResponse);
    }
    return queryRef;
  }

  private updateQueryRef(
    condition: { key: string; op: WhereFilterOp; value: string | string[] },
    index: number,
    orderByKey: any,
    order: any,
    queryRef: Query
  ): { orderByKeyVal: any; orderVal: any; queryRefVal: Query } {
    const key =
      condition.key === "id"
        ? firebase.default.firestore.FieldPath.documentId()
        : condition.key;
    if (index === 0 && !condition.key?.includes(".")) {
      orderByKey = key;
      order = condition.key === "id" ? "asc" : "desc";
    } else if (condition.key?.includes(".")) {
      orderByKey = firebase.default.firestore.FieldPath.documentId();
    }
    if (condition.value instanceof Array) {
      condition.value = condition.value.splice(0, 10);
    }
    queryRef = queryRef.where(key, condition?.op, condition?.value);
    return {
      orderByKeyVal: orderByKey,
      orderVal: order,
      queryRefVal: queryRef,
    };
  }

  push_prev_startAt(prev_first_doc: DocumentSnapshot<T>) {
    this.prev_strt_at.push(prev_first_doc);
  }

  ngOnDestroy() {
    this.subs$.next();
    this.subs$.complete();
  }
}

Unfortunately, I would not be able to create a stack blitz project because of the complexity and unable to share access to the project because of the confidentiality.

from angularfire.

Sapython avatar Sapython commented on June 3, 2024

Ok, nothing here seems, that can cause connection issue.

I have a suggestions

  1. Comment all the modules of your app in app.module.ts
  2. Turn it into a blank app by commenting every route in app.routing
  3. Comment every imported module created by you in app.module.ts
  4. Comment every module of Firebase except provideFirestore and initializeApp in app.module.ts
  5. Then call a simple getDoc request inside the app.component.ts

Check if Firebase is working.

  • If yes then the issue has to do with this service or the project itself
  • but if it fails then it means Firebase is the issue.

from angularfire.

kshkrao3 avatar kshkrao3 commented on June 3, 2024

Finally, after much digging around the internet, I've resolved this issue by the below steps. However, I was not able to find the root cause for the same.

My application uses a combination of modular v9 library and compatibility library for a few functionalities. This is where I had to use the initialization features of the application for both modular and compatibility libraries. I presume this could have been one of the reasons for the issue. Based on this presumption, I eliminated the dependency on the compatibility libraries and started using modular v9 features.

My code now looks like the below:

app.module.ts

import { APP_ID, NgModule } from "@angular/core";
import { FormsModule } from "@angular/forms";
import { BrowserModule } from "@angular/platform-browser";
import { RouterModule } from "@angular/router";
import { NgbModule } from "@ng-bootstrap/ng-bootstrap";

import { AppRoutingModule } from "./app-routing.module";
import { AppComponent } from "./app.component";
import { SharedModule } from "./shared/shared.module";
import { CoreModule } from "./core/core.module";
// Firebase/Firestore
import { getApp, initializeApp, provideFirebaseApp } from "@angular/fire/app";
import { provideAuth, getAuth, connectAuthEmulator } from "@angular/fire/auth";
import {
  initializeAppCheck,
  provideAppCheck,
  ReCaptchaEnterpriseProvider,
} from "@angular/fire/app-check";
import {
  initializeFirestore,
  persistentLocalCache,
  persistentMultipleTabManager,
  provideFirestore,
  connectFirestoreEmulator,
  Firestore,
  getFirestore,
} from "@angular/fire/firestore";
import { environment } from "src/environments/environment";
import { NgxSpinnerModule } from "ngx-spinner";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import {
  getAnalytics,
  provideAnalytics,
  ScreenTrackingService,
  UserTrackingService,
} from "@angular/fire/analytics";
import { getPerformance, providePerformance } from "@angular/fire/performance";
import { LocationStrategy, PathLocationStrategy } from "@angular/common";
import { FullCalendarModule } from "@fullcalendar/angular"; // must go before plugins

declare global {
  // eslint-disable-next-line no-var
  var FIREBASE_APPCHECK_DEBUG_TOKEN: boolean | string | undefined;
}
if (!environment.production) {
  self.FIREBASE_APPCHECK_DEBUG_TOKEN = environment.appCheckDebug; // set to <debugToken> that registered with App-Check in Firebase Console
}
@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserAnimationsModule,
    BrowserModule,
    NgbModule,
    FormsModule,
    RouterModule,
    AppRoutingModule,
    SharedModule,
    CoreModule,
    NgxSpinnerModule,
    FullCalendarModule,
    provideFirebaseApp(() => initializeApp(environment.firebaseConfig)),
    provideFirestore(() => {
      let firestore: Firestore;
      if (!environment.production) {
        firestore = getFirestore(getApp());
        connectFirestoreEmulator(firestore, "localhost", 8089);
      } else {
        firestore = initializeFirestore(getApp(), {
          localCache: persistentLocalCache({
            tabManager: persistentMultipleTabManager(),
          }),
          experimentalAutoDetectLongPolling: true,
          experimentalLongPollingOptions: {
            timeoutSeconds: 30,
          },
        });
      }
      return firestore;
    }),
    provideAuth(() => {
      const auth = getAuth();
      if (!environment.production) {
        connectAuthEmulator(auth, "http://localhost:9099", {
          disableWarnings: true,
        });
      }
      return auth;
    }),
    providePerformance(() => getPerformance(getApp())),
    provideAppCheck(() =>
      initializeAppCheck(getApp(), {
        provider: new ReCaptchaEnterpriseProvider(environment.recaptchaSiteKey),
        isTokenAutoRefreshEnabled: true,
      })
    ),
    provideAnalytics(() => getAnalytics(getApp())),
  ],
  providers: [
    ScreenTrackingService,
    UserTrackingService,
    { provide: LocationStrategy, useClass: PathLocationStrategy },
    {
      provide: APP_ID,
      useValue: "serverApp",
    },
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}


lazyload.service.ts


//// This Service would be a non singleton instance since it is used by multiple list modules and data has to be fresh for each module
//// Hence, its not provided through Service module, but rather its provided through individual list components
import { Injectable, OnDestroy, inject } from "@angular/core";
import { WhereFilterOp } from "@firebase/firestore-types";
import { Subject } from "rxjs";
import { takeUntil, map } from "rxjs/operators";
import { NgxSpinnerService } from "ngx-spinner";
import {
  collection,
  query,
  Query,
  where,
  documentId,
  orderBy,
  limit,
  startAfter,
  DocumentSnapshot,
  CollectionReference,
  collectionSnapshots,
  Firestore,
} from "@angular/fire/firestore";
import { traceUntilFirst } from "@angular/fire/performance";
@Injectable({
  providedIn: "any",
})
export class LazyloadService<T> implements OnDestroy {
  tableData: T[] = [];
  where: { key: string; op: WhereFilterOp; value: string | string[] }[] | null =
    [];
  limit = 10;
  collection = "";
  dataLoading = false;
  doneLoading = false;
  spinnerName = "pageLoader";
  // save last document in snapshot of items received
  private lastInResponse: DocumentSnapshot<T> | any;
  // keep the array of first document of previous pages
  private prev_strt_at: DocumentSnapshot<T>[] = [];
  subs$: Subject<void> = new Subject<void>();
  private firestore: Firestore = inject(Firestore);
  private spinnerService: NgxSpinnerService = inject(NgxSpinnerService);

  loadItems({ isReset = false, isNext = false }) {
    if (isReset) {
      this.dataLoading = false;
      this.doneLoading = false;
      this.tableData = [];
      this.spinnerName = "pageLoader";
    }
    if (this.doneLoading) {
      this.spinnerService.hide("pageLoader");
      this.spinnerService.hide("contentLoader");
    }
    if (this.dataLoading || this.doneLoading) {
      return;
    }
    this.spinnerService.show(this.spinnerName);
    this.dataLoading = true;
    const collectionRef = collection(this.firestore, this.collection);
    const q = this.createQueryRef(collectionRef, isNext);
    return collectionSnapshots(q).pipe(
      traceUntilFirst(this.collection),
      takeUntil(this.subs$),
      map((response) => {
        this.doneLoading = response.length === 0;
        this.spinnerService.hide(this.spinnerName);
        this.lastInResponse = response[response?.length - 1];
        this.push_prev_startAt(this.lastInResponse);
        response.forEach((record) => {
          // Avoid pushing duplicates
          if (
            this.tableData.filter((item: any) => item["id"] === record?.id)
              .length <= 0
          ) {
            this.tableData.push({
              ...(record?.data() as T),
              id: record?.id,
            });
          }
        });
        this.dataLoading = false;
        return;
      })
    );
  }

  private createQueryRef(ref: CollectionReference, isNext: boolean): Query {
    let queryRef: Query;
    let orderByKey: any = "modifiedDate";
    let order: any = "desc";
    const conditions: any = [];
    if (this.where) {
      this.where.forEach((condition, index) => {
        const key = condition.key === "id" ? documentId() : condition.key;
        if (index === 0 && !condition.key?.includes(".")) {
          orderByKey = key;
          order = condition.key === "id" ? "asc" : "desc";
        } else if (condition.key?.includes(".")) {
          orderByKey = documentId();
        }
        if (condition.value instanceof Array) {
          condition.value = condition.value.splice(0, 10);
        }
        conditions.push(where(key, condition?.op, condition?.value));
      });
    }
    conditions.push(limit(this.limit));
    if (orderByKey !== "date") {
      conditions.push(orderBy(orderByKey, order));
    }
    if (isNext && this.lastInResponse) {
      conditions.push(startAfter(this.lastInResponse));
    }
    queryRef = query(ref, ...conditions);
    return queryRef;
  }

  push_prev_startAt(prev_first_doc: DocumentSnapshot<T>) {
    this.prev_strt_at.push(prev_first_doc);
  }

  ngOnDestroy() {
    this.subs$.next();
    this.subs$.complete();
  }
}


However, even after the above changes, I was getting the same behavior, which when further inspected, I noticed many of them were using @angular/[email protected] and I was using @angular/[email protected]. I went ahead and downgraded to the v7.x version, which is when I started getting a different issue before I could validate the actual issue.

ERROR FirebaseError: Expected type 'Query', but it was: a custom dh object

One of the suggestions was to downgrade the Firebase version as well to v9, which I followed. This, however, ended up resolving the issue but created one more issue which was related to the version of rxfire library used by angular/[email protected].

Ultimately, I had to override the rxfire version for angular/fire like below and I was successfully able to resolve the actual issue I had.

"overrides": {
    "@angular/fire@^7.6.1": {
      "rxfire@^6.0.0": "6.0.3"
    }
  }

I'm still not sure if this was a problem with @angular/[email protected]. I did not dare to test this with @angular/[email protected] as I had lost many days digging around resolving the issue.

Hope this helps someone.

from angularfire.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.