如何在另一个函数的complition上调用一个函数?

时间:2021-03-01 15:54:35

标签: angular rxjs observable

我正在通过建立一个小型房地产代理作为宠物项目来学习 Angular。我有一个带有表单的模式,用户可以在其中添加新的 Estate - 基本数据和图片。首先,我想将其保存到 Cloudinary,然后将网址保存到 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[];
}

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

根据此链接向 Cloudinary API 发布请求(在 for 循环中):cloudinary docs
模态提交按钮触发 handleSaveEstate()。然后我想将所有图片上传到 Cloudinary 并从响应中获取 url 到 arrray 并在调用 addEstate(urls) 时完成。
首先调用 Friebase,然后填充数组:response

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

1 个答案:

答案 0 :(得分:2)

这里有多个问题。

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

试试下面的方法

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)
      );
    })
  );
}
相关问题