Reputation: 63
I'm learning Angular by building a small Real Estate agency as a pet project. I have modal with a form in which user can add new Estate - basic data and pictures. Firstly i want to save it to the Cloudinary and then save urls in to Firebase.
I cannot make it work in order, instead Firebase is called first with empty urls array. I found there is function finalize() in rxjs but it doesn't work either.
CloudinaryService :
uploadImage(vals: any): Observable<any>{
return this.http
.post('https://api.cloudinary.com/v1_1/<my_cloudinary>/image/upload', vals)
}
FirebaseService & IEstate:
addEstate(estate: IEstate){
return this.firestore.collection('estate').doc().set(estate);
}
export interface IEstate{
id?: string;
city: string;
street: string;
links: string[];
}
EstateCreateComponent:
form: FormGroup;
estates: IEstate[] = [];
files: File[] = [];
handleSaveEstate(){
let result : string[];
this.uploadToCloudinary()
.pipe(
finalize(() => this.addEstate(result)))
.subscribe(res => result = res,
error =>{
console.log(error);
},
() => {
console.log('complete')
});
}
addEstate(links: string[]): void{
let data = {
city: this.form.value.city,
street: this.form.value.street,
links: links
} as IEstate;
this.firebaseService.addEstate(data).then((res) =>{
console.log(res);
});
}
uploadToCloudinary(){
const data = new FormData();
let urls: string[] = [];
for (let i = 0; i < this.files.length; i++) {
data.append('file', this.files[i]);
data.append('upload_preset', 'my_name_upload')
data.append('cloud_name', 'my_cloudinary_name')
this.cloudinary.uploadImage(data).subscribe(res =>{
urls.push(res.secure_url);
});
}
return of(urls);
}
Post requests(in for loop) to the Cloudinary API are made according to this link: cloudinary docs
Modal submit button triggers handleSaveEstate(). Then i want upload all pictures to Cloudinary and get the urls from the response in to the arrray and at complition of that call addEstate(urls).
Friebase is called first and then the array is populated :
How do i make these calls in order?
Upvotes: 0
Views: 40
Reputation: 31125
There are multiple issues here.
forkJoin
with Array#map
.urls
synchronously from the async calls. You need to return the observable and subscribe where the response is required.from
function to convert the promise to a function. You either need to convert the promise to an observable or vice-versa. I've illustrated the former using from
.switchMap
to switch from one observable to another.Try the following
form: FormGroup;
estates: IEstate[] = [];
files: File[] = [];
handleSaveEstate() {
let result: string[];
this.uploadToCloudinary().pipe(
switchMap(urls => this.addEstate(urls))
).subscribe({
next: (res) => {
console.log(res); // <-- response from `this.firebaseService.addEstate()`
},
error: (error) => {
console.log(error);
},
complete: () => {
console.log('complete')
}
});
}
addEstate(links: string[]): Observable<any> {
let data = {
city: this.form.value.city,
street: this.form.value.street,
links: links
} as IEstate;
from(this.firebaseService.addEstate(data));
}
uploadToCloudinary(): Observable<any> {
const data = new FormData();
return forkJoin(
this.files.map(file => {
data.append('file', file);
data.append('upload_preset', 'my_name_upload')
data.append('cloud_name', 'my_cloudinary_name')
return this.cloudinary.uploadImage(data).pipe(
map(res => res.secure_url)
);
})
);
}
Upvotes: 2