【问题标题】:Chaining HTTP call in Angular在 Angular 中链接 HTTP 调用
【发布时间】:2021-03-30 20:56:22
【问题描述】:

我正在尝试使用他们的 API 获取 Google Places 并获取包含“photo_reference”属性的响应正文。有了这个属性,我想获取 Google Place Image 并调用第二个 API。

我有一个可以搜索地点的输入字段。通过输入字符串并单击搜索按钮,将调用此方法:

@Component({
  selector: 'app-search',
  templateUrl: './search.component.html',
  styleUrls: ['./search.component.css']
})
export class SearchComponent implements OnInit {
  private lng: number;
  private lat: number;
  private place_id: string;
  private listOfPoi: GoogleLocation[];

  constructor(
    private gs: GoogleService,
    private ds: DataService,
    private router: Router
    ) { }

  ngOnInit(): void {
    this.ds.getLocation().subscribe(loc => this.listOfPoi = loc);
  }

searchPoi(location: string): void {
    this.router.navigate(['/poi']);    
    this.gs.getPoi(location).pipe(
      map((response) => response)
    ).subscribe((data: GoogleResponse) => {
      if(data.status === "OK") {
        this.ds.setLocation(data.results); //data.results is an array of locations
      }      
    });
  }

在我的另一个组件中,我尝试获取位置并将它们映射到具有属性 imgUrl 的新对象中。 我想将它们保存在一个数组中。

export class SightseeingViewComponent implements OnInit {
  listOfPoi: LocationWithImage[];

  constructor(private ds: DataService, private gs: GoogleService) {}

  ngOnInit(): void {
    this.ds.getLocation().subscribe(
      (loc) =>
        (this.listOfPoi = loc.map((loc) => {
          return {
            ...loc,
            imgUrl:            
            this.gs.getImage(loc.photos[0].photo_reference).toString(),
          };
        }))
    );
  }
}

但我的问题是 img src="[object Object]" 它应该是字符串!

我的问题是这一行this.gs.getImage(loc.photos[0].photo_reference).toString() 我试图用一个随机硬编码的 img Url 替换这一行,它可以工作。图像已显示,但我无法使用此方法将 URL 作为字符串检索。 当然 toString() 不起作用,但我不知道我还能做什么?

这是谷歌定位模型:

//The model of a google location object from the API response (getLocationInfo)
export class GoogleResponse {
    constructor(
        public results: GoogleLocation[],
        public status: string
        ) {}

}

export class GoogleLocation {
    constructor(
        public formatted_address: string,
        public geometry: Locations,
        public icon: string,
        public name: string,
        public photos: PhotoInfo[],
        public place_id: string,
        public reference: string,
        public type: string[]
    ) {}
}

export interface LocationWithImage extends GoogleLocation {
    imgUrl?: string;
}
...

编辑:

这是我的服务: 有了这个,我调用了我的后端,它通过其 API 从 Google 获取 photo_reference

@Injectable({
  providedIn: 'root',
})
export class GoogleService {
  url: string = 'http://localhost:3000/';

  constructor(private http: HttpClient) {}

  getLocationInfo(location: string): Observable<GoogleResponse> {
    console.log(location);
    const headers = new HttpHeaders({
      'Content-Type': 'application/json',
    });
    return this.http.post<GoogleResponse>(
      this.url + 'googleplace/',
      { name: location },
      { headers: headers }
    );
  }

  getPoi(location: string): Observable<GoogleResponse> {
    console.log(location);
    const headers = new HttpHeaders({
      'Content-Type': 'application/json',
    });
    return this.http.post<GoogleResponse>(
      this.url + 'googlepoi/',
      { name: location },
      { headers: headers }
    );
  }

  getImage(photoRef: string): Observable<string> {
    console.log(photoRef);
    const headers = new HttpHeaders({
      'Content-Type': 'application/json',
    });
    return this.http.post<string>(
      this.url + 'googlephoto/',
      { photoRef: photoRef },
      { headers: headers }
    );
  }


}


这是我从其他组件发送和检索数据所需的其他服务

@Injectable({
  providedIn: 'root'
})
export class DataService {

  private googleLocationSource = new Subject<GoogleLocation[]>();

  constructor() { }

  public getLocation(): Observable<GoogleLocation[]> {
    return this.googleLocationSource.asObservable();
  }

  public setLocation(gl: GoogleLocation[]) {
    return this.googleLocationSource.next(gl);
  }
 

【问题讨论】:

  • 大概 getImage 返回一个 observable 数据,不清楚为什么您认为 toString 会神奇地使其同步。请给minimal reproducible example
  • 是的,我知道...我怎样才能得到它的字符串值?我尝试了 pipe、forkjoin、map、switchmap 等,但没有工作.. 好的!我提供了更多信息,这有帮助吗?
  • 目前还不清楚您尝试了什么,我希望forkJoin 可以工作(假设您想扇出多个可观察对象然后获得所有结果)。

标签: javascript angular typescript api rxjs


【解决方案1】:

我的问题是这一行this.gs.getImage(loc.photos[0].photo_reference).toString()

是的,在 observable 上调用 toString() 是行不通的! :-)

您需要订阅该 observable 才能接收其结果。有一些“Higher Order Mapping Operators”可以为您完成此操作,因此您不必处理嵌套订阅。在这种情况下,我们可以使用switchMap

但是,它有点复杂,因为您想要调用返回数组中的每个元素。我们可以将每个位置映射到一个 observable 调用以获取图像并使用 forkJoin 创建一个单独的 observable,该 observable 发出一个包含各个 observable 的结果的数组:

this.ds.getLocation().pipe(
  switchMap(locations => forkJoin(
    locations.map(loc => this.gs.getImage(loc.photos[0].photo_reference))
  )
  .pipe(
    map(imgUrls => imgUrls.map(
      (imgUrl, i) => ({ ...locations[i], imgUrl })
    ))
  ))
)
.subscribe(
    locations => this.listOfPoi = locations
);

这里的流程是:

  • switchMap 接收位置并订阅由 forkJoin 创建的 observable
  • forkJoin 创建一个 observable,它将从所有单独的 getImage() 调用中发出一个结果数组(图像 url)。
  • map 接收图像 url 数组并将其映射到包含图像 url 的位置数组
  • subscribe 只是接收最终的数组

【讨论】:

  • 我明白了,谢谢。事实上,我想调用每个元素,所以它有点复杂。我尝试了您的解决方案,但它说 locations.map 的类型为 unknown 也是 Property 'pipe' does not exist on type 'OperatorFunction&lt;unknown, unknown[]&gt;'. this.ds.getLocation() 将从 GoogleLocation[] btw 类型返回一个 Observable
  • 我添加了更多信息,我不知道他们是否有帮助.. 再次感谢
  • 看起来我的括号放错了位置。更新了!
  • 非常感谢!它似乎工作,没有错误!现在刚刚遇到 CORS 问题,但这是另一个问题:) 再次感谢!
猜你喜欢
  • 2016-03-10
  • 2018-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-18
  • 1970-01-01
  • 2020-08-31
相关资源
最近更新 更多