Table of Contents

TMS FNC Places — Guides

Set Request.Query for keyword searches. Set Request.Coordinate and Request.Radius for nearby searches. Call GetPlaces and handle OnGetPlaces to receive results.

Controlling the nearby search radius

A nearby search normally returns every match around a center coordinate using the backend's default radius. When the Google backend is switched to the Places API (New) (see Google Places (New) API below), the nearby search call accepts an explicit ARadius parameter, in meters, so you can widen or narrow the search area for the use case — a small radius for "coffee shops within walking distance", a large one for "hospitals in the region".

ARadius is passed to SearchNearby (and its SearchNearbyResult / SearchNearbySync overloads) as the last parameter. Passing 0, or omitting it, falls back to a 50000 meter default. The parameter only affects requests made through the Places API (New) — the legacy Google Places nearby search always applies its own fixed radius regardless of the value passed.

procedure TForm1.SearchNearbyWithRadius;
var
  Location: TTMSFNCMapsCoordinateRec;
begin
  Location.Latitude := 51.5074;
  Location.Longitude := -0.1278;

  { TMSFNCGooglePlaces1 is a TTMSFNCGooglePlaces component with
    UseGooglePlacesNew set to True (see places-google-places-new.pas).
    The ARadius parameter (in meters) is sent as the "radius" value of
    the locationRestriction circle in the searchNearby JSON request body.
    When ARadius is 0 or omitted, the component defaults to 50000 meters.
    ARadius has no effect when UseGooglePlacesNew is False: the legacy
    Google Places nearby search always uses a fixed radius. }
  TMSFNCGooglePlaces1.SearchNearby(Location, 'cafe', nil, '', nil, '', mlmDefault, 1500);
end;

procedure TForm1.TMSFNCGooglePlaces1SearchNearby(Sender: TObject;
  const ARequest: TTMSFNCPlacesRequest;
  const ARequestResult: TTMSFNCCloudBaseRequestResult);
var
  I: Integer;
begin
  { Every item in ARequest.Items now falls within the requested
    1500 meter radius of Location. }
  for I := 0 to ARequest.Items.Count - 1 do
  begin
    { Inspect ARequest.Items[I].Description, .Vicinity, .Coordinate, ... }
  end;
end;

Place details

To retrieve detailed information about a specific place, call GetPlaceDetails with the place identifier returned in a previous search result.

Place photos

Place results include Photos (TTMSFNCPlacesPhotoItems). Each TTMSFNCPlacesPhotoItem contains a photo reference that can be used to retrieve the image URL via GetPhotoURL.

Service backends

Set the Service property to switch between available places providers: Google (psGoogle, the default), Here (psHere), Geo Apify (psGeoApify), Azure (psAzure), Bing (psBing), and TomTom (psTomTom). See ITMSFNCPlacesService for the interface implemented by each backend.

{ Switch the places component to the TomTom backend: }
TMSFNCPlaces1.Service := psTomTom;
TMSFNCPlaces1.APIKey := 'YOUR-TOMTOM-API-KEY';

Each backend has its own API key format and its own quota/pricing model, so changing Service typically also means updating APIKey for the newly selected provider. Changing Service re-initializes the underlying service instance; issue any pending request again after switching backends.

Google Places (New) API

The Google backend supports two generations of the Google Places REST API: the original Google Places API (query-string requests against maps.googleapis.com), and the newer Google Places API (New) (JSON POST requests against places.googleapis.com, with the API key and a field mask sent as request headers instead of URL parameters). Set UseGooglePlacesNew to True to opt into the newer API — it changes the host, endpoint paths, and request/response shape used for text search, nearby search, autocomplete, and place-detail lookups, while keeping the same TTMSFNCPlacesRequest / TTMSFNCPlacesItem result shape your event handlers already consume. UseGooglePlacesNew is False by default, so existing projects keep using the original Google Places API until they opt in.

UseGooglePlacesNew is available on TTMSFNCPlaces for the psGoogle backend, but the request methods that use it (SearchByText, SearchNearby, GetPlaceDetail) are only published on the Google-specific TTMSFNCGooglePlaces component. Use TTMSFNCGooglePlaces when you need to call these methods directly; use TTMSFNCPlaces with Service := psGoogle when GetAutoComplete is enough, or when you only need to select a backend for another workflow that drives requests internally.

procedure TForm1.EnableGooglePlacesNew;
begin
  { TMSFNCGooglePlaces1 is a TTMSFNCGooglePlaces component (unit
    FMX.TMSFNCGooglePlaces), the Google-specific places component whose
    search methods are public. TTMSFNCPlaces also exposes
    UseGooglePlacesNew, but only TTMSFNCGooglePlaces publishes the
    SearchByText/SearchNearby methods used to issue requests. }
  TMSFNCGooglePlaces1.APIKey := 'YOUR-GOOGLE-API-KEY';

  { UseGooglePlacesNew switches the component from the legacy REST
    endpoints (maps.googleapis.com, query-string parameters, API key in
    the URL) to the Places API (New): places.googleapis.com, JSON POST
    bodies, and the API key plus a field mask sent as request headers
    (X-Goog-Api-Key, X-Goog-FieldMask). Set it once before issuing any
    request; changing it later re-initializes the underlying service. }
  TMSFNCGooglePlaces1.UseGooglePlacesNew := True;
end;

procedure TForm1.SearchByTextGooglePlacesNew(const AQuery: string);
var
  Location: TTMSFNCMapsCoordinateRec;
begin
  Location.Latitude := 51.5074;
  Location.Longitude := -0.1278;

  { With UseGooglePlacesNew enabled, this call posts a JSON body to
    /v1/places:searchText on places.googleapis.com instead of issuing a
    GET request to the legacy textsearch endpoint. The result shape
    returned to OnSearchByText / OnSearchByTextResult is unchanged. }
  TMSFNCGooglePlaces1.SearchByText(AQuery, Location);
end;

procedure TForm1.TMSFNCGooglePlaces1SearchByText(Sender: TObject;
  const ARequest: TTMSFNCPlacesRequest;
  const ARequestResult: TTMSFNCCloudBaseRequestResult);
var
  I: Integer;
begin
  for I := 0 to ARequest.Items.Count - 1 do
  begin
    { Inspect ARequest.Items[I].Description, .Address, .Coordinate, ... }
  end;
end;

See also