Reputation: 1060
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);
}
Upvotes: 0
Views: 88
Reputation: 14740
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 forkJoinforkJoin
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 urlUpvotes: 1