When utilizing AngularFire with Firebase Firestore Database, users may encounter instances where data duplication occurs on

Currently facing a challenge in my Angular 13.1 Project utilizing @angular/fire 7.4.1 for database management

The issue arises consistently across various screens where data from Firestore Database is displayed, particularly on List screens. The lists are being populated with multiple duplicates of the records stored in my database.

An example can be seen below in the Teams list screen: https://i.sstatic.net/G4x2K.gif

Interestingly, upon navigating to another route and returning to the affected screen, the correct number of entries is displayed.

https://i.sstatic.net/Is8kG.gif

I've considered that it might relate to an initialization issue within the application but haven't been able to pinpoint the cause. I have experience working with AngularFire on previous projects involving Firestore Database.

The list mentioned above is loaded through an ngOnInit() call as shown:

private loadTeamsList(){
if(!this.currentUser.teams) return;

for(var i = 0;i < this.currentUser.teams.length; i++){

    /*

      Where this.currentUser.teams[i] represents the Firebase document id of the team
      
    */

    this.teamsService.getTeam(this.currentUser.teams[i]).subscribe( team => {
        this.teamsList.push(team);
    })
 }
}

Current record being read contains only one teamId as seen here: https://i.sstatic.net/TvDqL.png

This leads to calling the Team Service function :

export class TeamService {

   private endpointPrefix = '/teams'

   constructor(private firebaseService: FirebaseService) { }

   getTeam(teamId: string): Observable<Team>{
     return this.firebaseService.getById(teamId,this.endpointPrefix);
   }

...

Further leading to the 'parent' service, FirebaseService, where majority of service calls are made.

@Injectable({
providedIn: 'root'
})

export class FirebaseService{

constructor(private firestore: Firestore){ }

...

getById(id: string | null,endpointPrefix: string): Observable<any>{
    const ref = doc(this.firestore,endpointPrefix +  `/${id}`);
    return docData(ref, { idField: 'id' }) as Observable<any>;
}

getAll(endpointPrefix: string): Observable<any[]> {
    const ref = collection(this.firestore, endpointPrefix);
    return collectionData(ref, { idField: 'id' }) as Observable<any[]>;
}

get firestoreRef(){
    return this.firestore;
}

Attempts to prevent duplicates using the includes() method within subscriptions have not resolved the issue, as the array continues to populate with duplicates. Is there something crucial missing at the service level or am I incorrectly populating the array? This issue persists across all screens retrieving data from the database.

Answer №1

Discovered a workaround solution to resolve my issue! The key was related to the services and transforming my subscribes into promises. Following Frank's explanation, it seems that the subscriptions were retaining the data (which I now realize is cached) and then triggering subscribe with that data, causing it to appear 'duplicated' on the UI

//Function for making service call to fetch list data (getAll)
async getAllAsync(endpointPrefix: string){
    let response : any[] = [];

    const ref = collection(this.firestore, endpointPrefix);
    const q = query(ref);

    const querySnapshot = await getDocs(q);
    querySnapshot.forEach((doc) => {
        let resDocument = {
            id : doc.id,
            ...doc.data()
        }
        response.push(resDocument);
    });

    if(response){
        return response;
    } else {
        console.log("No response")
        return null;
    }
}

//Function for making service call to fetch specific document data (getById)
async getByIdPromise(id: string | null,endpointPrefix: string): Promise<any>{
    let response : any;

    const ref = doc(this.firestore,endpointPrefix +  `/${id}`); 
    const docSnap = await getDoc(ref);

    if(docSnap.data()){
        response = docSnap.data();
    } else {
        // doc.data() will be undefined in this case
        console.log("No such document!");
    }
    
    if(response){
        return response;
      } else {
        console.log("No records with ladder ID found")
        return null
    }
}

Subsequently, I updated my TeamService Call:

getTeam(teamId: string): Promise<any>{
  return this.firebaseService.getByIdPromise(teamId,this.endpointPrefix);
}

Finally, I replaced .subscribe with .then in my component.

this.teamsService.getTeam(this.currentUser.teams[i]).then( team => {
        this.teamsList.push(team);
})

Answer №2

Whenever a change occurs in the database, the Firestore SDK will trigger your code to receive a comprehensive list of the data that you are subscribed to. It is important to clear any existing items in your user interface before inserting new items from the database.

To ensure this process works smoothly, make sure to reset this.teamsList within your loadTeamsList function prior to appending the items fetched from getTeam:

private loadTeamsList(){
  if(!this.currentUser.teams) return;

  this.teamsList = []; // Resetting the list to empty before populating it with data from the database

  for(var i = 0; i < this.currentUser.teams.length; i++){
    this.teamsService.getTeam(this.currentUser.teams[i]).subscribe( team => {
        this.teamsList.push(team);
    })
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Every time I click on a single button, all the text inputs get updated simultaneously

One issue I encountered is with a component featuring increment and decrement buttons. These buttons are meant to interact with specific products, yet when clicked, all text inputs update simultaneously instead of just the intended one. COMPONENT HTML: &l ...

The data table fails to display updated information from the data source

After updating the data-array (FileDto), I am unable to see any changes reflected in the Datatable. I have tested outputting the data using ngFor, and it works perfectly fine. Here is the HTML code: <ngx-datatable class="material striped" [rows]= ...

Make TypeScript parameter optional if it is not supplied

I am working with an interface that defines scenes and their parameters: export interface IScene<R extends string> { path: R; params?: SceneParams; } The SceneParams interface looks like this: export interface SceneParams { [key: string]: s ...

GitHub Actions causing build failure in Angular project exclusively

I've encountered an issue where the GitHub Action workflow fails to compile an Angular project, even though it works fine on my local machine and that of my colleagues. It's worth noting that I'm using npm ci instead of npm install. The err ...

What could be the rationale behind the optional chaining operator not being fully compatible with a union of classes in TypeScript?

Imagine I have a combination of classes: type X = ClassA | ClassB | ClassC; Both ClassA and ClassC have a shared method called methodY. Why is it that I can't simply use the optional chaining operator to call for methodY? class ClassA { methodY ...

Typescript enhances the functionality of the Express Request body

I need help with the following code snippet: const fff = async (req: express.Request, res: express.Response): Promise<void> => {...} How can I specify that req.body.xxx exists? I want it to be recognized when I reference req.body.xxx as a propert ...

Angular 5: Display a blank URL with the source until the variables are resolved

In my template, if I have: <img src="/somepath/{{user?.UserGuid}}.png" /> When user is not yet resolved, the ?. prevents evaluating UserGuid, resulting in: <img src="/somepath/.png" /> Is there a way to prevent this without using *ngIf or c ...

I am unable to add a new property to the request object in the Express framework

My goal is to add a new property to the request object in typescript. Here's the code snippet I'm using: import { request, Request, response, Response } from "express"; ((req: Request, res: Response) => { console.log(req.user); ...

Issue when utilizing TypeScript MongoDB Definitions (Unable to locate namespace)

I am currently working on implementing MongoDB typings that I installed using the following command: npm install @types/mongodb -D Now, I want to utilize these types within a function like this: export default async function insertOne(collection:any, da ...

Async pipe in Angular does not work with my custom observables

I've been trying to implement the async pipe in my template, but I'm encountering difficulties retrieving data from my API. To store and retrieve the data, I have utilized a behavior subject to create an observable. However, when I attempt to dis ...

Trouble with scrolling on Kendo chart while using mobile device

I am facing an issue with multiple kendo charts on my website. These charts have panning and zooming enabled, but in the mobile view, they take up 100% of the width which causes touch events to not work properly for scrolling. I attempted to attach an even ...

Setting up SSL/TLS certificates with Axios and Nest JS

I have a Nest JS application set up to send data from a local service to an online service. However, the requests are not working because we do not have an SSL certificate at the moment. Can anyone provide guidance on configuring Axios in Nest JS to accept ...

Access to Firebase using Google authentication is currently restricted (permission denied)

Currently, I am utilizing Firebase to authenticate users with Google in my Angular project, "project1." When signing anonymously into Firebase, everything runs smoothly. However, if I attempt to sign in with Google using the popup feature, an error occurs: ...

Isolated Modules in Angular Version 17 and Beyond

Having worked with an earlier version of Angular, I am facing issues with my navbar routes not working properly on my Contact Page. Can someone shed some light on this for me? If you want to take a look at the code, here is the link: https://github.com/Lo ...

Changes made to an array in a called method using TypeScript do not appear in the calling function

The angular 6 calling-component-code I'm working with is as follows: this.appDowntimeService.getAllApplications(this.message, this.appDetails); Here's the service method being called: async getAllApplications(message: any[], appDetails: any[ ...

The CSS properties intended for ion-button elements are not taking effect

I'm attempting to set a background color when a ion-button is clicked or maintain the ion-ripple effect after it has filled the button in Ionic 4. I experimented with applying custom CSS states in global.scss, but encountered issues where the active ...

Launch another modal and then deactivate the initial modal

Having two Modals has presented a challenge for me when it comes to closing the first modal after the second one is opened. I attempted a solution, but it prevented the second Modal from opening altogether. This code snippet below belongs to the first Mo ...

The information is not displayed on the Angular multi-select dropdown

Having an issue where the data is stored in an object and when I try to map it to an ng multiselect dropdown, the values are not displaying in the dropdown. This is happening with Angular 7. <div class="form group mltslt" *ngIf="individual==true"> ...

NextJS and Context API throwing a Typescript error

I've been working on my _app.tsx file and here's the code snippet I have: import React from 'react' import type { AppProps } from 'next/app' /* Import Styles */ import '@themes/index.scss' /* Import Template */ imp ...

Error in util.js: process variable is not defined in Angular 15

As I work on integrating the Voice JavaScript SDK into my Angular 15 application, I encountered an error after installing the necessary npm packages. When running the app, a reference error is displayed in the browser console and the UI fails to load. Unca ...