Issue
I'm trying to add an item into my firestore with a picture, since the base64 picture is greater than 2Mb, I'm using firestore to store the image and get the url to set the corresponding field.
To do so, I'm sending my item to firebase with an empty field for the picture, then, I'm sending the picture to firebase storage. until here everything is ok, but when I'm trying to get the download url and set it to my item, it does not work.
here is my code:
Here my page where i'm adding a new item into firestore.
export class AddFoodPage implements OnInit {
...
addFood() {
this.setFood();
this.foodService.addFood(this.food, this.foodPicture.base64).then(() => {
this.presentAlert();
this.tagList = [];
this.ingredientList = [];
this.addFoodForm.reset();
});
}
...
private setFood() {
this.food = this.addFoodForm.value;
this.food.ingredientList = this.ingredientList;
this.food.specials = this.tagList;
this.foodPicture = this.imgService.getPicture();
this.food.photoUrl = '';
}
here my service for the item:
export class FoodService {
private foodCollection: AngularFirestoreCollection<FoodView>;
constructor(
private afs: AngularFirestore,
private authService: AuthService,
private storage: AngularFireStorage
) {
this.foodCollection = this.afs.collection('food');
}
async addFood(food: FoodView, base64String: string) {
this.authService.getUserData().subscribe((_user) => {
food.cookerName = _user.displayName;
food.cookerId = _user.uid;
from(this.foodCollection.add(food)).subscribe((addedFood) =>
this.uploadFoodImage(base64String, addedFood.id, food.cookerId)
);
});
}
private uploadFoodImage(
base64String: string,
foodId: string,
userId: string
) {
const filePath = `foods/${userId}/${foodId}`;
const fileRef = this.storage.ref(filePath);
const task: AngularFireUploadTask = fileRef.putString(
base64String,
'base64',
{ contentType: 'image/png' }
);
return from(task).pipe(
switchMap(
(result) => {
return fileRef.getDownloadURL();
}
// Upload Task finished, get URL to the image
),
switchMap((photoUrl) => {
// Set the URL to the food document
const uploadPromise = this.afs
.doc(`food/${foodId}`)
.set(photoUrl, { merge: true });
console.log(photoUrl);
return from(uploadPromise);
})
);
}
In the above code, the code in the switchMap function are not executed, and I don't understand why, do I miss something ? The picture is saved into firebase storage, but then the document is not update in firestore.
here is my food model:
export class FoodView {
fid: string;
cookerId: string;
cookerName: string;
title: string;
photoUrl: string;
ingredientList: string[] = [];
type: string;
hasAllergen: boolean;
specials: string[];
origin: string;
price: number;
quantity: number;
}
Solution
You can devide Observables into two different kinds: "hot" and "cold" observables. With hot observables you've got the source of the emitted values outside of the function that is represented by the observable. Cold observables on the other hand create the source in its own function. So for a cold observable to emit any values the body has to run at least once.
In your example the form(task)
seems to create a cold observable. So to first create the source of data, you need to call the function by subscribing to it.
To shorten it up: Just add an .subscribe()
after your pipe.
return from(task).pipe(
switchMap(
(result) => {
return fileRef.getDownloadURL();
}
// Upload Task finished, get URL to the image
),
switchMap((photoUrl) => {
// Set the URL to the food document
const uploadPromise = this.afs
.doc(`food/${foodId}`)
.set(photoUrl, { merge: true });
console.log(photoUrl);
return from(uploadPromise);
})
).subscribe();
Answered By - Philipp Honsel
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.