首页 > 解决方案 > 如何在编译另一个函数时调用一个函数?

问题描述

我正在通过建立一个小型房地产中介作为宠物项目来学习 Angular。我有一个表单,用户可以在其中添加新的 Estate - 基本数据和图片。首先,我想将其保存到 Cloudinary,然后将 url 保存到 Firebase。

我无法使其按顺序工作,而是首先使用空 urls 数组调用 Firebase。我发现 rxjs 中有函数 finalize() 但它也不起作用。

云服务:

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[];
}

房地产创建组件:

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);
  }

根据此链接向 Cloudinary API 发布请求(在 for 循环中):cloudinary docs
Modal submit button triggers handleSaveEstate()。然后我想将所有图片上传到 Cloudinary 并从对数组的响应中获取 url,并在调用 addEstate(urls) 时获取。
首先调用 Friebase,然后填充数组:回复

我如何按顺序拨打这些电话?

标签: angularrxjsobservable

解决方案


这里有多个问题。

  1. 循环内的订阅可能会导致多个开放订阅。相反,您可以将 RxJSforkJoinArray#map.
  2. 您不能urls从异步调用中同步返回。您需要返回 observable 并在需要响应的地方订阅。
  3. 您可以使用 RxJSfrom函数将 Promise 转换为函数。您要么需要将承诺转换为可观察的,反之亦然。我已经用from.
  4. 使用映射运算符喜欢switchMap从一个可观察对象切换到另一个。

尝试以下

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)
      );
    })
  );
}

推荐阅读