Membuat Autocomplete Google Place API Pada Laravel
Tutorial ini menunjukkan cara membuat alamat Google Autocomplete menggunakan Google Place API. Beberapa situs web secara otomatis menyarankan alamat saat Anda mengisi form alamat, mengeklik alamat, dan mengisi kolom lainnya, seperti nomor jalan 1, nomor jalan 2, kota, negara bagian, kode pos, dll. Anda mungkin memiliki melihatnya selesai.
Jadi apa yang Anda butuhkan untuk mengikuti tutorial ini?
- Menyiapkan proyek laravel:
composer create-project laravel/laravel googleautocomplete
- Instal Guzzle:
composer require guzzlehttp/guzzle
- Google API Key yang valid
- anda bisa membaca dokumentasi langsung pada Google Place Autocomplete API: Google Place Autocomplete API
Mari buat controller dengan metode indeks yang mengembalikan form
php artisan make:controller GoogleAutocompleteController
//GoogleAutocompleteController.php
<?php
namespace App\Http\Controllers;
use Illuminate\View\View;
use Illuminate\Http\Request;
class GoogleAutocompleteController extends Controller
{
public function index(): View
{
return view('form');
}
}
pada resource/views/form.blade.php
Saya telah membuat form sederhana menggunakan bootstrap dengan field alamat, field kota, field negara bagian, field kode pos, dan field negara.
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Google autocomplete</div>
<div class="card-body">
<div class="form-group">
<label for="streetaddress">Street address</label>
<input type="text" class="form-control ui-widget autocomplete-google" id="street_address_1">
</div>
<div class="form-group">
<label for="streetaddress2">Street address 2</label>
<input type="text" class="form-control" id="street_address_2">
</div>
<div class="form-group">
<label for="city">City</label>
<input type="text" class="form-control" id="city">
</div>
<div class="form-group">
<label for="state">State</label>
<input type="text" class="form-control" id="state">
</div>
<div class="form-group">
<label for="postcode">Postcode</label>
<input type="text" class="form-control" id="postcode">
</div>
<div class="form-group">
<label for="country">Country</label>
<input type="text" class="form-control" id="country">
</div>
</div>
</div>
</div>
</div>
</div>
Dalam form di atas, kami menambahkan widget ui kelas ke field alamat jalan. Ini karena kami menggunakan library autocomplete jQuery untuk memunculkan alamat yang dikembalikan oleh Google API saat pengguna benar-benar mulai mengetik alamat ke field alamat jalan. Kelas ini akan mengaktifkan autocomplate .
Terakhir, daftarkan routes di web.php
untuk menampilkan form.
Route::get('/autocomplete',[GoogleAutocompleteController::class,'index']);
form ini ditampilkan saat Anda mengunjungi URL /autocomplete
di browser Anda.
bagian 2
Bagian ini menggunakan library autocomplete jQuery dan Places API. Google Places API mengembalikan ID Tempat dan mengisi semua field dalam form berdasarkan ID Tempat.
Langkah 1: kunjungi library jQuery Autocomplete
copy jquery-ui.js
dan jquery-ui.css
dan paste dalam app.blade.php
Sekarang layouts/app.blade.php
saya terlihat seperti ini
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Scripts -->
<script src="{{ asset('js/app.js') }}" defer></script>
<!-- Fonts -->
<link rel="dns-prefetch" href="//fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<!-- Styles -->
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
<link rel="stylesheet" href="//code.jquery.com/ui/1.13.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
</head>
<body>
<div id="app">
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand" href="{{ url('/') }}">
{{ config('app.name', 'Laravel') }}
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- Left Side Of Navbar -->
<ul class="navbar-nav me-auto">
</ul>
<!-- Right Side Of Navbar -->
<ul class="navbar-nav ms-auto">
<!-- Authentication Links -->
@guest
@if (Route::has('login'))
<li class="nav-item">
<a class="nav-link" href="{{ route('login') }}">{{ __('Login') }}</a>
</li>
@endif
@if (Route::has('register'))
<li class="nav-item">
<a class="nav-link" href="{{ route('register') }}">{{ __('Register') }}</a>
</li>
@endif
@else
<li class="nav-item dropdown">
<a id="navbarDropdown" class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" v-pre>
{{ Auth::user()->name }}
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="{{ route('logout') }}"
onclick="event.preventDefault();
document.getElementById('logout-form').submit();">
{{ __('Logout') }}
</a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" class="d-none">
@csrf
</form>
</div>
</li>
@endguest
</ul>
</div>
</div>
</nav>
<main class="py-4">
@yield('content')
@yield('script')
</main>
</div>
</body>
</html>
Seperti yang Anda lihat, saya menambahkan @yield('script')
di atas. Dengan kata lain, apa pun yang Anda wrap dalam skrip Anda akan disisipkan di sini. Kemudian wrap javascript di dalam kode @section('script')//..js @endsection
di form.blade.php
.
Langkah 2: Buka Google Places API
Jenis dapat ditampilkan. Anda dapat membatasi hasil dari request autocomplete tempat ke jenis tertentu dengan meneruskan parameter jenis. Parameter ini menentukan jenis atau kumpulan jenis, seperti yang tercantum dalam Jenis Tempat. Jika tidak ada yang ditentukan, semua tipe dikembalikan. diperlukan jenis alamat
Salin URL ini, buka postman atau browser Anda, tempel dan tekan tombol kirim.
https://maps.googleapis.com/maps/api/place/autocomplete/json?input= kathmandu nepal &types=address&key=YOUR_KEY
Anda harus mendapatkan respons seperti ini:
Catatan: Saya tertarik dengan place_id
dalam response. Dengan place_id
kita bisa mendapatkan negara, nomor jalan, kode pos, kota, dll.
Langkah 3: Buka config/services.php
dan atur key
'googlekey'=>[
'key'=> env('GOOGLE_KEY', null),
],
dan di file .env
Anda
GOOGLE_KEY=YOUR_GOOGLE_KEY
Langkah 4: Mari buat routes
Route::get('/placeid',[ GoogleAutocompleteController::class,'getPlaceId'])->name('placeid');
GoogleAutocompleteController.php
terlihat seperti ini
<?php
namespace App\Http\Controllers;
use Illuminate\View\View;
use Illuminate\Http\Request;
class GoogleAutocompleteController extends Controller
{
public function index(): View
{
return view('form');
}
public function getPlaceId(Request $request)
{
//get user typed address via ajax request
}
}
Langkah 5: Tambahkan script jQuery ke form.blade.php
Tambahkan script jQuery ke form.blade.php
untuk mengaktifkan dropdown autocomplete dan tambahkan request ajax untuk mengirim alamat yang dimasukkan oleh pengguna ke endpoint /placeId
.
<script>
$(document).ready(function() {
$(".autocomplete-google").autocomplete({
source: function(request, response) {
$.ajax({
url: '/placeid',
type: 'GET',
dataType: "json",
data: {
inputData: request.term,
},
success: function(data) {
response(data);
}
});
},
});
});
</script>
Resource/form.blade.php
lengkap terlihat seperti ini:
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Google autocomplete</div>
<div class="card-body">
<div class="form-group">
<label for="streetaddress">Street address</label>
<input type="text" class="form-control ui-widget autocomplete-google" id="street_address_1">
</div>
<div class="form-group">
<label for="streetaddress2">Street address 2</label>
<input type="text" class="form-control" id="street_address_2">
</div>
<div class="form-group">
<label for="city">City</label>
<input type="text" class="form-control" id="city">
</div>
<div class="form-group">
<label for="state">State</label>
<input type="text" class="form-control" id="state">
</div>
<div class="form-group">
<label for="postcode">Postcode</label>
<input type="text" class="form-control" id="postcode">
</div>
<div class="form-group">
<label for="country">Country</label>
<input type="text" class="form-control" id="country">
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@section('script')
<script>
$(document).ready(function() {
$(".autocomplete-google").autocomplete({
source: function(request, response) {
$.ajax({
url: '/placeid',
type: 'GET',
dataType: "json",
data: {
inputData: request.term,
},
success: function(data) {
response(data);
}
});
},
});
});
</script>
@endsection
Langkah6: Sekarang mari buat kelas Handler hanya untuk autocomplete.
Anda dapat meletakkan semua kode Anda di getPlaceId()
dari GoogleAutocompleteController
, tetapi untuk membersihkan kode Anda, sebaiknya pindahkan semua logika Anda ke kelas PHP yang terpisah.
Mari buat AutocompleteHandler.php
di dalam folder Integrasi dari direktori aplikasi.
<?php
namespace App\Integration;
use GuzzleHttp\Client;
class AutocompleteHandler
{
public const BASE_URL = "https://maps.googleapis.com/maps/api/place";
public string $key;
public function __construct()
{
$this->key = config('services.googlekey.key');
}
public function placeId(string $address)
{
//
}
}
Pada kode di atas, kita menetapkan URL dasar dan key yang akan kita gunakan nanti. Metode placeId(string $address) di atas menerima alamat sebagai parameter string yang diterima dari metode getPlaceId()
GoogleAutocompleteController
sebagai berikut:
Langkah7: Masukkan AutocompleteHandler.php
ke GoogleAutocompleteController.php
dan teruskan alamat dari getPlaceId()
di GoogleAutocompleteController.php
ke placeId()
di AutocompleteHandler.php
.
GoogleAutocompleteController.php
terlihat seperti ini:
<?php
namespace App\Http\Controllers;
use Illuminate\View\View;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use App\Integration\AutocompleteHandler;
class GoogleAutocompleteController extends Controller
{
public $googleAutocomplete;
public function __construct(AutocompleteHandler $googleAutocomplete)
{
$this->googleAutocomplete = $googleAutocomplete;
}
public function index(): View
{
return view('form');
}
public function getPlaceId(Request $request): JsonResponse
{
return $this->googleAutocomplete->placeId($request->inputData);
}
}
Di atas mengambil alamat sebagai inputData
dan kemudian meneruskan inputData
ini sebagai parameter alamat ke placeId()
.
Langkah8: Mari kita mulai dengan AutocompleteHandler.php
<?php
namespace App\Integration;
use GuzzleHttp\Client;
class AutocompleteHandler {
public const BASE_URL = "https://maps.googleapis.com/maps/api/place";
public string $key;
public function __construct()
{
$this->key = config('services.googlekey.key');
}
public function placeId(string $address)
{
$url= https://maps.googleapis.com/maps/api/place/autocomplete/json?input=kathmandu&types=address&key=YOUR_API_KEY
// build the readable url with http_build_query and sprintf()
try {
// step1: instantiate GuzzleHttp client
// step2: hit the url
// step3: get json response
// step4: convert json to array
// step5: loop over the predictions array of response
// step6: and return place_id as id and description as label
} catch (\Exception $e) {
//catch error
}
}
}
Jadi Handler.php
autocomplete final terlihat seperti ini:
<?php
namespace App\Integration;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use GuzzleHttp\Client;
class AutocompleteHandler
{
public const BASE_URL = "https://maps.googleapis.com/maps/api/place";
public string $key;
public function __construct()
{
$this->key = config('services.googlekey.key');
}
public function placeId(string $address): JsonResponse
{
$url = sprintf(
'%s/autocomplete/json?%s',
self::BASE_URL,
http_build_query([
'input' => $address,
'types' => 'address',
'key' => $this->key,
])
);
try {
$client = new Client();
$response = $client->request('get', $url);
$responseJson = $response->getBody()->getContents();
$responseArray = json_decode($responseJson, true);
return response()->json(collect($responseArray['predictions'])->map(
fn ($value) =>
[
'id' => $value['place_id'],
'label' => $value['description'],
]
));
} catch (\Exception $e) {
return response()->json([
'error' => $e->getMessage(),
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
}
Di atas, kami menggunakan collect()
untuk mengonversi $responseArray
menjadi collection, memetakannya, dan mengembalikan place_id
dan deskripsi.Saat Anda mulai mengisi form, itu akan mulai menyarankan alamat seperti yang ditunjukkan di bawah ini.
bagian 3
Ini adalah bagian terakhir dari autocomplete Google Places. Di bagian ini, pengguna memilih satu alamat dari dropdown dan mengisi kolom form lainnya.
Sekarang kita membutuhkan place_id
dari respon sebelumnya. Jika Anda pergi ke: https://maps.googleapis.com/maps/api/place/details/json?place_id=EhtOZXBhbCBUYXIsIEthdGhtYW5kdSwgTmVwYWwiLiosChQKEgk9yaxKzhjrORHvFQWGXi5RGhIUChIJv6p7MIoZ6zkR6EUGN8KEY
anda mendapatkan response dalam format ini.
Jadi saya mendapatkan hasilnya sebagai response dan semua data yang saya butuhkan seperti jalan, kota, kode pos, dll
. Ada di dalam address_components
.
Langkah 1: Di atas kita mengembalikan place_id
sebagai id. Saat pengguna mengklik alamat tersebut, kami membuat request ajax lain untuk mendapatkan semua detail tempat berdasarkan place_id
.
Jadi setelah sumber Anda dapat menambahkan pilih seperti di bawah ini
select: function(event, ui) {
var placeId = ui.item.id;
console.log(placeId)
}
Jadi kode jQuery terlihat seperti ini:
<script>
$(document).ready(function() {
$(".autocomplete-google").autocomplete({
source: function(request, response) {
$.ajax({
url: '/placeid',
type: 'GET',
dataType: "json",
data: {
inputData: request.term,
},
success: function(data) {
response(data);
}
});
},
select: function(event, ui) {
var placeId = ui.item.id;
console.log(placeId)
}
});
});
</script>
Mengklik alamat yang dipilih akan menampilkan placeId
output pada console.
Langkah 2: Mari buat endpoint yang menerima placeId
dan mengembalikan detail lokasi berdasarkan placeId
Pada Route web.php
Route::get('address',[ GoogleAutocompleteController::class,'findAddressBasedOnPlaceId'])->name('address');
Jadi sekarang web.php terlihat seperti ini
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\GoogleAutocompleteController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/autocomplete',[ GoogleAutocompleteController::class,'index']);
Route::get('/placeid',[ GoogleAutocompleteController::class,'getPlaceId'])->name('placeid');
Route::get('address',[ GoogleAutocompleteController::class,'findAddressBasedOnPlaceId'])->name('address');
Auth::routes();
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
Langkah3: Mari buat metode ini di GoogleAutocompleteController.php
public function findAddressBasedOnPlaceId(Request $request)
{
//get place_id via ajax request when user select the address from dropdown suggestions
}
Langkah 3: Dari respons di atas yang dikembalikan dari API, kita dapat melihat bahwa data ada di address_components
dan setiap respons mungkin atau mungkin tidak mengembalikan kode pos, nama area, dll. untuk place_id
itu. Jadi, Anda harus memeriksa secara manual apakah key yang diperlukan ada di respons untuk mencegah kesalahan halaman. Misalnya, jika respons berisi kode pos, kembalikan kode pos, dll. Jadi, menulis pernyataan if-else untuk setiap key, mari buat fungsi helper yang mengembalikan key yang diperlukan jika ada di respons.
Tambahkan method ini di AutocompleteHandler.php
Anda
public function getDataFromAddressComponent(array $addressComponents, string $searchFor): ?string
{
return collect($addressComponents)->map(fn ($addressComponent) => collect($addressComponent['types'])->contains($searchFor) ? $addressComponent['long_name'] : null)->filter()->first();
}
Di atas kita mengulang $addressComponents
dan memeriksa untuk melihat apakah ada $searchFor
dalam array itu. Jika benar, mereturn yang lain dan mereturn nol. Namun, di sini kami menggunakan collection.
atau Anda dapat melakukan ini
foreach ($addressComponents as $address) {
if (in_array($searchFor, $address['types'])) {
return $address['long_name'];
}
}
return null;
Langkah 4: Di GoogleAutocompleteController.php
, terima ID lokasi dari request ajax dan teruskan ke metode addressBasedOnPlaceId()
AutocompleteHandler.php
. Ini akan mengembalikan detail lokasi.
public function findAddressBasedOnPlaceId(Request $request): JsonResponse
{
return $this->googleAutocomplete->addressBasedOnPlaceId($request->placeId);
}
Langkah5: Mari kirim placeId melalui ajax ke metode findAddressBasedOnPlaceId()
Tambahkan getAddressDetails(placeId)
select: function(event, ui) {
var placeId = ui.item.id;
getAddressDetails(placeId);
}
Fungsi getAddressDetails()
membuat request ajax ke titik akhir/alamat
Sekarang resource/form.blade.php
terlihat seperti ini:
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Google autocomplete</div>
<div class="card-body">
<div class="form-group">
<label for="streetaddress">Street number</label>
<input type="text" class="form-control ui-widget autocomplete-google" id="street_address_1">
</div>
<div class="form-group">
<label for="streetaddress2">Street address 2</label>
<input type="text" class="form-control" id="street_address_2">
</div>
<div class="form-group">
<label for="city">City</label>
<input type="text" class="form-control" id="city">
</div>
<div class="form-group">
<label for="state">State</label>
<input type="text" class="form-control" id="state">
</div>
<div class="form-group">
<label for="postcode">Postcode</label>
<input type="text" class="form-control" id="postcode">
</div>
<div class="form-group">
<label for="country">Country</label>
<input type="text" class="form-control" id="country">
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
@section('script')
<script>
$(document).ready(function() {
$(".autocomplete-google").autocomplete({
source: function(request, response) {
$.ajax({
url: '/placeid',
type: 'GET',
dataType: "json",
data: {
inputData: request.term,
},
success: function(data) {
response(data);
}
});
},
select: function(event, ui) {
var placeId = ui.item.id;
getAddressDetails(placeId);
}
});
});
function getAddressDetails(placeId) {
$.ajax({
url: "/address",
type: 'GET',
dataType: "json",
data: {
placeId: placeId,
},
success: function(data) {
$('#country').val(data.country);
$('#city').val(data.locality);
$('#postcode').val(data.postal_code);
$('#state').val(data.state);
$('#street_address_1').val(data.streetNumber);
$('#street_address_2').val(data.streetName);
},
catch: function(error) {
console.log('error');
}
});
}
</script>
@endsection
Di atas, saya mendapatkan hasil sukses, saya memasukkan negara, kota, kode pos dan id negara bagian dalam form, tetapi API belum siap untuk mengembalikan detail lokasi berdasarkan id lokasi.
Langkah 6: Di AutocompleteHandler.php
buat addressBasedOnPlaceId()
yang menerima id tempat yang dikirim oleh findAddressBasedOnPlaceId()
di GoogleAutocompleteController.php
.
public function addressBasedOnPlaceId(string $placeId): JsonResponse
{
$url = $url = // build the readable url with http_build_query and sprintf()
https://maps.googleapis.com/maps/api/place/details/json?place_id=EhtOZXBhbCBUYXIsIEthdGhtYW5kdSwgTmVwYWwiLiosChQKEgk9yaxKzhjrORHvFQWGXi5RGhIUChIJv6p7MIoZ6zkR6rGN8Rt8E7U&key=YOUR_KEY
);
try {
// step1: instantiate GuzzleHttp client
// step2: hit the url
// step3: get json response
// step4: convert json to array
// step5: return required data such as street name, city,postcode, country etc
} catch (\Exception $e) {
//catch error
}
}
Langkah7: AutocompleteHandler.php final terlihat seperti ini
<?php
namespace App\Integration;
use GuzzleHttp\Client;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
class AutocompleteHandler
{
public const BASE_URL = "https://maps.googleapis.com/maps/api/place";
private $key;
public function __construct()
{
$this->key = config('services.googlekey.key');
}
public function getDataFromAddressComponent(array $addressComponents, string $searchFor): ?string
{
return collect($addressComponents)->map(fn ($addressComponent) => collect($addressComponent['types'])->contains($searchFor) ? $addressComponent['long_name'] : null)->filter()->first();
}
public function placeId(string $address): JsonResponse
{
$url = sprintf(
'%s/autocomplete/json?%s',
self::BASE_URL,
http_build_query([
'input' => $address,
'types' => 'address',
'key' => $this->key,
])
);
try {
$client = new Client();
$response = $client->request('get', $url);
$responseJson = $response->getBody()->getContents();
$responseArray = json_decode($responseJson, true);
return response()->json(collect($responseArray['predictions'])->map(
fn ($value) =>
[
'id' => $value['place_id'],
'label' => $value['description'],
]
));
} catch (\Exception $e) {
return response()->json([
'error' => $e->getMessage(),
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
public function addressBasedOnPlaceId(string $placeId): JsonResponse
{
$url = sprintf(
'%s/details/json?%s',
self::BASE_URL,
http_build_query([
'place_id' => $placeId,
'key' => $this->key,
])
);
try {
$client = new Client();
$response = $client->request('get', $url);
$responseJson = $response->getBody()->getContents();
$responseArray = json_decode($responseJson, true);
return response()->json([
'streetNumber' => $this->getDataFromAddressComponent($responseArray['result']['address_components'], 'street_number'),
'streetName' => $this->getDataFromAddressComponent($responseArray['result']['address_components'], 'route'),
'locality' => $this->getDataFromAddressComponent($responseArray['result']['address_components'], 'locality'),
'state' => $this->getDataFromAddressComponent($responseArray['result']['address_components'], 'administrative_area_level_1'),
'administrative_area_level_2' => $this->getDataFromAddressComponent($responseArray['result']['address_components'], 'administrative_area_level_2'),
'country' => $this->getDataFromAddressComponent($responseArray['result']['address_components'], 'country'),
'postal_code' => $this->getDataFromAddressComponent($responseArray['result']['address_components'], 'postal_code')
]);
} catch (\Exception $e) {
return response()->json(['error' => $e->getMessage(), 'exception' => get_class($e)], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
}
Jadi saya mengembalikan nomor jalan, nama jalan, wilayah, negara bagian, kode pos, dan negara sebagai response dan mengisi nilai-nilai tersebut di field form lainnya. selamat mencoba :)