0

I'm trying to get Google Places with their API and get a response body that contains a "photo_reference" property. With this property, I want to get the Google Place Image and call a second API.

I have an input field that can search for places. By entering a string and clicking on the search button, this method will get called:

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

In my other component, I try to get the locations and map them into a new object with the property imgUrl. I want to save them in an array.

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

But my problem is the img src="[object Object]" it should be the string!

My problem is this line this.gs.getImage(loc.photos[0].photo_reference).toString() I tried to replace this line with a random hardcoded img Url and it works. The image are shown but I cannot retrieve the URL as string with this method. Of course toString() is not working but I have no clue what else I can do?

This is the google location model:

//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; } ... 

EDIT:

This is my service: With this, I make a call to my backend which is fetching the photo_reference from Google via its API

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

Here is my other service which is needed to send and retrieve data from other components

@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); } 
3
  • Presumably getImage returns an observable of the data, and it's unclear why you thought toString would magically make it synchronous. Please give a minimal reproducible example. Commented Mar 30, 2021 at 21:01
  • Yeah I know... How can I get the string value of that? I tried with pipe, forkjoin, map, switchmap and so on but not working.. Okay! I provided more information, does that help? Commented Mar 30, 2021 at 21:30
  • It's unclear what you've tried, I'd expect forkJoin to work (given you want to fan out to multiple observables then get all of the results). Commented Mar 30, 2021 at 21:34

1 Answer 1

1

My problem is this line this.gs.getImage(loc.photos[0].photo_reference).toString()

Yes, calling toString() on an observable isn't going to work ! :-)

You need to subscribe to that observable to receive its result. There are a few "Higher Order Mapping Operators" that can do this for you, so you don't have to deal with nested subscriptions. In this case, we can use switchMap.

However, it's a little more complex because you want to make a call for each element in the returned array. We can map each location to an observable call to get the image and use forkJoin to create a single observable that emits an array containing the results of the individual observables:

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

The flow here is:

  • switchMap receives the locations and subscribes to observable created by forkJoin
  • forkJoin creates an observable that will emit an array of the results (image urls) from all the individual getImage() calls.
  • map receives the array of image urls and maps it to an array of locations that include the image url
  • subscribe simply receives the final array
Sign up to request clarification or add additional context in comments.

4 Comments

I see thanks. Indeed I want to call for each element, so it's a bit complicated. I tried your solution but it says that locations.map is of type unknown also Property 'pipe' does not exist on type 'OperatorFunction<unknown, unknown[]>'. this.ds.getLocation() will return an Observable from type GoogleLocation[] btw
I added some more information, I don't know if they help.. Thanks again
looks like I had a misplaced paren. updated!
Thank you a lot! It seems to work and no error!! Just getting CORS problem now but this is another problem:) Thanks again!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.