it is passed a lot of time from the last time that I worked on Angular and Firebase and I am finding the following simple problem trying to use AngularFire 2 in order to retrieve the entire objects from a Firestore collection (it means the document ID + the document data that must be put into a model object).
So this is my situation.
First of all this is my package.json file:
{
"name": "fintness-tracker",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"private": true,
"dependencies": {
"@angular/animations": "~13.3.0",
"@angular/cdk": "^13.3.8",
"@angular/common": "~13.3.0",
"@angular/compiler": "~13.3.0",
"@angular/core": "~13.3.0",
"@angular/flex-layout": "^13.0.0-beta.38",
"@angular/forms": "~13.3.0",
"@angular/material": "^13.3.8",
"@angular/platform-browser": "~13.3.0",
"@angular/platform-browser-dynamic": "~13.3.0",
"@angular/router": "~13.3.0",
"angularfire2": "^5.4.2",
"firebase": "^7.24.0",
"hammerjs": "^2.0.8",
"rxjs": "~7.5.0",
"rxjs-compat": "^6.6.7",
"tslib": "^2.3.0",
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "~13.3.6",
"@angular/cli": "~13.3.6",
"@angular/compiler-cli": "~13.3.0",
"@types/jasmine": "~3.10.0",
"@types/node": "^12.11.1",
"jasmine-core": "~4.0.0",
"karma": "~6.3.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.1.0",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "~1.7.0",
"typescript": "~4.6.2"
}
}
Then I have this simple Exercise model interface that will map a Firebase document:
export interface Exercise {
id: string;
name: string;
duration: number;
calories: number;
date?: Date;
state?: 'completed' | 'cancelled' | null;
}
And finally my NewTrainingComponent Angular component class, in its ngOnInit()
import { Component, OnInit, EventEmitter, Output } from '@angular/core';
import { NgForm } from '@angular/forms';
import { Exercise } from '../exercise.model';
import { TrainingService } from '../training.service';
import { AngularFirestore } from 'angularfire2/firestore';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Component({
selector: 'app-new-training',
templateUrl: './new-training.component.html',
styleUrls: ['./new-training.component.css']
})
export class NewTrainingComponent implements OnInit {
@Output()
trainingStart:EventEmitter<void> = new EventEmitter<void>();
//exercises: Exercise[] = [];
exercises: Observable<any>;
constructor(private trainingService: TrainingService,
private db: AngularFirestore) { }
ngOnInit(): void {
//this.exercises = this.trainingService.getAvailableExercises();
//this.exercises = this.db
this.db
.collection("availableExercises")
.snapshotChanges()
.pipe(
map((docArray) => {
return docArray.map((doc) => {
return {
id: doc.payload.doc.id,
...(doc.payload.doc.data() as Exercise),
};
});
})
)
.subscribe(result => {
console.log(result);
});
/*
this.db.collection('availableExercises').valueChanges().subscribe(result => {
console.log(result);
})
*/
}
onStartTraining(form: NgForm) {
this.trainingService.startExercise(form.value.exercise);
}
}
What is the problem?
The problem is that when I try to create my model object in this way:
return {
id: doc.payload.doc.id,
...(doc.payload.doc.data() as Exercise),
};
it give me the following error on the id property on my IDE:
'id' is specified more than once, so this usage will be overwritten.ts(2783)
Compiling I obtain the same error:
Error: src/app/training/new-training/new-training.component.ts:38:15 - error TS2783: 'id' is specified more than once, so this usage will be overwritten.
38 id: doc.payload.doc.id,
~~~~~~~~~~~~~~~~~~~~~~
src/app/training/new-training/new-training.component.ts:39:15
39 ...(doc.payload.doc.data() as Exercise),
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This spread always overwrites this property.
Error: src/app/training/new-training/new-training.component.ts:38:15 - error TS2783: 'id' is specified more than once, so this usage will be overwritten.
38 id: doc.payload.doc.id,
~~~~~~~~~~~~~~~~~~~~~~
src/app/training/new-training/new-training.component.ts:39:15
39 ...(doc.payload.doc.data() as Exercise),
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This spread always overwrites this property.
✖ Failed to compile.
If I remove this property and I use:
return {
//id: doc.payload.doc.id,
...(doc.payload.doc.data() as Exercise),
};
I obtain no error but when the console.log() print out my result it doesn't contains the id property.
Why? What is wrong with my code? What am I missing? How can I try to fix it?
This is because you have an id
property in your Exercice
interface.
Switching the order as follows should do the trick, according to this SO answer (I didn't test it):
return {
...(doc.payload.doc.data() as Exercise),
id: doc.payload.doc.id
};