I am having difficulty pinpointing the exact origin issue in my Angular 13.1 Project that uses @angular/fire 7.4.1 as its database.
The issue seems to apply to each screen that I am displaying data that comes from my Firestore Database , usually in the form of List screens. The arrays that populate the lists seem to overpopulate with multiple instances of the records that are currently stored in my Firestore Database
Below is a example of the Teams list , one of the screens that have the issue.
Note however that If I navigate to another route and then back to that screen, I am able to see the correct amount of data entries displayed.
I keep thinking that perhaps its an issue with initializing the application or something but I am scratching my head. I'm thinking that its something small and I hope it is. I have done previous project on Firestore Database using AngularFire.
The list above is populated like so from an ngOnInit() call :
private loadTeamsList(){
if(!this.currentUser.teams) return;
for(var i = 0;i < this.currentUser.teams.length; i++){
/*
Where this.currentUser.teams[i] is the Firebastore document id of the team
*/
this.teamsService.getTeam(this.currentUser.teams[i]).subscribe( team => {
this.teamsList.push(team);
})
}
}
The current record being read here is this , which contains only one teamId.
Which then 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);
}
...
Which leads to the main 'parent' service , the FirebaseService, where I try to generally make the majority of service calls.
@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;
}
I've tried the route of checking arrays within subscriptions using the includes() method as a way of preventing duplicates , but it would seem the array populates with duplicates regardless.
Am I missing something essential on the service level here? Or perhaps I'm not populating the array correctly. As mentioned earlier this happens on all screens where data is being read/retrieved from the database.
Found a workaround solution to my problem! It is mainly related to the services, and turning my subscribes into promises. As Frank describes above , looks like the subscriptions were keeping that data (which is have come to understand is cache) and then subscribe was firing off with that data making it 'duplicated' on the UI
//Service Call for getting 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;
}
}
//Service Call for getting 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!");
}
//return docData(ref, { idField: 'id' }) as Observable<any>;
if(response){
//console.log(response)
return response;
} else {
console.log("No records with ladder Id found")
return null
}
}
I then updated my TeamService Call :
getTeam(teamId: string): Promise<any>{
return this.firebaseService.getByIdPromise(teamId,this.endpointPrefix);
}
Finally changing my .subscribe to .then in my component.
this.teamsService.getTeam(this.currentUser.teams[i]).then( team => {
this.teamsList.push(team);
})