├── config └── filament-google-autocomplete-field.php ├── resources └── lang │ ├── he │ └── filament-google-autocomplete-field.php │ ├── tr │ └── filament-google-autocomplete-field.php │ ├── en │ └── filament-google-autocomplete-field.php │ └── it │ └── filament-google-autocomplete-field.php ├── src ├── FilamentGoogleAutocompleteServiceProvider.php ├── Concerns │ ├── CanFormatGoogleParams.php │ └── HasGooglePlaceApi.php └── Forms │ └── Components │ └── GoogleAutocomplete.php ├── LICENSE.md ├── composer.json ├── CHANGELOG.md └── README.md /config/filament-google-autocomplete-field.php: -------------------------------------------------------------------------------- 1 | env('GOOGLE_PLACES_API_KEY', ''), 6 | 'verify-ssl' => true, 7 | 'throw-on-errors' => false, 8 | 9 | ]; 10 | -------------------------------------------------------------------------------- /resources/lang/he/filament-google-autocomplete-field.php: -------------------------------------------------------------------------------- 1 | 'כתובת', 6 | 'autocomplete.placeholder' => 'הקלד כתובת לחיפוש...', 7 | 'autocomplete.searching.message' => 'מחפש מיקום בגוגל...', 8 | 'autocomplete.search.prompt' => 'הקלד מיקום לחיפוש באמצעות גוגל', 9 | 10 | ]; 11 | -------------------------------------------------------------------------------- /resources/lang/tr/filament-google-autocomplete-field.php: -------------------------------------------------------------------------------- 1 | 'Adres', 6 | 'autocomplete.placeholder' => 'Adres aramak için yazın...', 7 | 'autocomplete.searching.message' => 'Aranıyor...', 8 | 'autocomplete.search.prompt' => 'Arama yapmak için bir konum yaz', 9 | 10 | ]; 11 | -------------------------------------------------------------------------------- /resources/lang/en/filament-google-autocomplete-field.php: -------------------------------------------------------------------------------- 1 | 'Address', 6 | 'autocomplete.placeholder' => 'Search for an address...', 7 | 'autocomplete.searching.message' => 'Searching location on Google...', 8 | 'autocomplete.search.prompt' => 'Type a location to search using Google', 9 | 10 | ]; 11 | -------------------------------------------------------------------------------- /resources/lang/it/filament-google-autocomplete-field.php: -------------------------------------------------------------------------------- 1 | 'Indirizzo', 6 | 'autocomplete.placeholder' => 'Cerca un indirizzo...', 7 | 'autocomplete.searching.message' => 'Ricerca della posizione su Google in corso...', 8 | 'autocomplete.search.prompt' => 'Digita un luogo da cercare tramite Google.', 9 | 10 | ]; 11 | -------------------------------------------------------------------------------- /src/FilamentGoogleAutocompleteServiceProvider.php: -------------------------------------------------------------------------------- 1 | name('filament-google-autocomplete-field') 14 | ->hasConfigFile() 15 | ->hasTranslations(); 16 | } 17 | 18 | public function packageBooted(): void 19 | { 20 | // 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Concerns/CanFormatGoogleParams.php: -------------------------------------------------------------------------------- 1 | 0) { 14 | $result = array_map(function ($country) { 15 | return sprintf('country:%s|', $country); 16 | }, $countries); 17 | 18 | return rtrim(implode('', $result), '|'); 19 | } 20 | 21 | return null; 22 | } 23 | 24 | public function getFormattedPlaceTypes(string|array $placeTypes): ?string 25 | { 26 | $placeTypes = Arr::wrap($placeTypes); 27 | 28 | if (count($placeTypes) > 0) { 29 | $result = array_map(function ($placeType) { 30 | return sprintf('%s|', $placeType); 31 | }, $placeTypes); 32 | 33 | return rtrim(implode('', $result), '|'); 34 | } 35 | 36 | return null; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Tapp Network 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tapp/filament-google-autocomplete-field", 3 | "description": "Filament plugin that provides a Google Autocomplete field", 4 | "keywords": [ 5 | "Tapp Network", 6 | "laravel", 7 | "Address", 8 | "Google Autocomplete", 9 | "Google Places API", 10 | "Filament", 11 | "PHP", 12 | "filament-google-autocomplete-field" 13 | ], 14 | "homepage": "https://github.com/tapp/filament-google-autocomplete-field", 15 | "license": "MIT", 16 | "authors": [ 17 | { 18 | "name": "Andreia Bohner", 19 | "email": "andreia.bohner@tappnetwork.com", 20 | "role": "Developer" 21 | } 22 | ], 23 | "require": { 24 | "php": "^8.2", 25 | "spatie/laravel-package-tools": "^1.16", 26 | "filament/filament": "^3.0-stable", 27 | "illuminate/contracts": "^10.0||^11.0||^12.0", 28 | "skagarwal/google-places-api": "^3.0" 29 | }, 30 | "require-dev": { 31 | "larastan/larastan": "^2.9|^3.0", 32 | "laravel/pint": "^1.14", 33 | "nunomaduro/collision": "^8.1.1||^7.10.0", 34 | "orchestra/testbench": "^8.22.0||^9.0.0||^10.0.0", 35 | "pestphp/pest": "^2.34||^3.0", 36 | "pestphp/pest-plugin-arch": "^2.7||^3.0", 37 | "pestphp/pest-plugin-laravel": "^2.3||^3.0", 38 | "pestphp/pest-plugin-livewire": "^2.1||^3.0", 39 | "phpstan/extension-installer": "^1.3", 40 | "phpstan/phpstan-deprecation-rules": "^1.1||^2.0", 41 | "phpstan/phpstan-phpunit": "^1.3||^2.0", 42 | "spatie/laravel-ray": "^1.35" 43 | }, 44 | "autoload": { 45 | "psr-4": { 46 | "Tapp\\FilamentGoogleAutocomplete\\": "src/" 47 | } 48 | }, 49 | "autoload-dev": { 50 | "psr-4": { 51 | "Tapp\\FilamentGoogleAutocomplete\\Tests\\": "tests/", 52 | "Workbench\\App\\": "workbench/app/" 53 | } 54 | }, 55 | "scripts": { 56 | "post-autoload-dump": "@composer run prepare", 57 | "clear": "@php vendor/bin/testbench package:purge-filament-google-autocomplete-field --ansi", 58 | "prepare": "@php vendor/bin/testbench package:discover --ansi", 59 | "build": [ 60 | "@composer run prepare", 61 | "@php vendor/bin/testbench workbench:build --ansi" 62 | ], 63 | "start": [ 64 | "Composer\\Config::disableProcessTimeout", 65 | "@composer run build", 66 | "@php vendor/bin/testbench serve" 67 | ], 68 | "analyse": "vendor/bin/phpstan analyse", 69 | "test": "vendor/bin/pest", 70 | "test-coverage": "vendor/bin/pest --coverage", 71 | "format": "vendor/bin/pint" 72 | }, 73 | "config": { 74 | "sort-packages": true, 75 | "allow-plugins": { 76 | "pestphp/pest-plugin": true, 77 | "phpstan/extension-installer": true 78 | } 79 | }, 80 | "extra": { 81 | "laravel": { 82 | "providers": [ 83 | "Tapp\\FilamentGoogleAutocomplete\\FilamentGoogleAutocompleteServiceProvider" 84 | ] 85 | } 86 | }, 87 | "minimum-stability": "dev", 88 | "prefer-stable": true 89 | } 90 | -------------------------------------------------------------------------------- /src/Forms/Components/GoogleAutocomplete.php: -------------------------------------------------------------------------------- 1 | name($name); 51 | } 52 | 53 | public static function make(string $name): static 54 | { 55 | $static = app(static::class, ['name' => $name]); 56 | $static->configure(); 57 | $static->columnSpanFull(); 58 | 59 | return $static; 60 | } 61 | 62 | /** 63 | * @return array 64 | */ 65 | public function getChildComponents(): array 66 | { 67 | $components = []; 68 | 69 | $components[] = Forms\Components\Select::make($this->getAutocompleteName()) 70 | ->label($this->getAutocompleteLabel()) 71 | ->native(false) 72 | ->dehydrated(false) 73 | ->allowHtml() 74 | ->live() 75 | ->placeholder($this->getAutocompletePlaceholder()) 76 | ->searchDebounce($this->getAutocompleteSearchDebounce()) // 2 seconds 77 | ->searchingMessage(__('filament-google-autocomplete-field::filament-google-autocomplete-field.autocomplete.searching.message')) 78 | ->searchPrompt(__('filament-google-autocomplete-field::filament-google-autocomplete-field.autocomplete.search.prompt')) 79 | ->searchable() 80 | ->hint(new HtmlString(Blade::render(''))) 81 | ->columnSpan($this->getAutocompleteFieldColumnSpan()) 82 | ->getSearchResultsUsing(function (string $search, Set $set): array { 83 | $set($this->getAutocompleteName(), null); 84 | $response = $this->getPlaceAutocomplete($search); 85 | 86 | $result = $response->collect(); 87 | 88 | return $this->getPlaceAutocompleteResult($result); 89 | }) 90 | ->afterStateUpdated(function (?string $state, Set $set) { 91 | if ($state === null) { 92 | foreach ($this->getWithFields() as $field) { 93 | $set($field->getName(), null); 94 | } 95 | 96 | return; 97 | } 98 | 99 | $data = $this->getPlace($state); 100 | 101 | $googleFields = $this->getFormattedApiResults($data); 102 | 103 | foreach ($this->getWithFields() as $field) { 104 | // Check if the field is a Hidden component or has getExtraInputAttributes method 105 | $fieldExtraAttributes = $field instanceof Forms\Components\Hidden 106 | ? $field->getExtraAttributes() 107 | : $field->getExtraInputAttributes(); 108 | 109 | $googleFieldName = count($fieldExtraAttributes) > 0 && isset($fieldExtraAttributes['data-google-field']) ? $fieldExtraAttributes['data-google-field'] : $field->getName(); 110 | 111 | $googleFieldValue = count($fieldExtraAttributes) > 0 && isset($fieldExtraAttributes['data-google-value']) ? $fieldExtraAttributes['data-google-value'] : 'long_name'; 112 | 113 | // if the field contains combined values 114 | if (str_contains($googleFieldName, '{')) { 115 | $value = $this->replaceFieldPlaceholders($googleFieldName, $googleFields, $googleFieldValue); 116 | } else { 117 | // bc: Fixes issue with Carson City, NV. No administrative_area_level_2 provided in search result. 118 | $value = ''; 119 | if (isset($googleFields[$googleFieldName][$googleFieldValue])) { 120 | $value = $googleFields[$googleFieldName][$googleFieldValue] ?: ''; 121 | } 122 | } 123 | 124 | $set($field->getName(), $value); 125 | $field->callAfterStateUpdated(); 126 | } 127 | }); 128 | 129 | $addressData = Arr::map( 130 | $this->getWithFields(), 131 | function (Component $component) { 132 | return $component; 133 | } 134 | ); 135 | 136 | $allComponents = array_merge($components, $addressData); 137 | 138 | return [ 139 | Forms\Components\Grid::make($this->getAddressFieldsColumns()) 140 | ->schema( 141 | $allComponents 142 | ), 143 | ]; 144 | } 145 | 146 | protected function replaceFieldPlaceholders($googleField, $googleFields, $googleFieldValue) 147 | { 148 | preg_match_all('/{(.*?)}/', $googleField, $matches); 149 | 150 | foreach ($matches[1] as $item) { 151 | $valueToReplace = isset($googleFields[$item][$googleFieldValue]) ? $googleFields[$item][$googleFieldValue] : ''; 152 | 153 | $googleField = str_ireplace('{'.$item.'}', $valueToReplace, $googleField); 154 | } 155 | 156 | return $googleField; 157 | } 158 | 159 | protected function getPlaceAutocompleteResult($result) 160 | { 161 | if ($this->placesApiNew) { 162 | if (isset($result['suggestions']) && ! empty($result['suggestions'])) { 163 | $searchResults = collect($result['suggestions'])->mapWithKeys(function (array $item, int $key) { 164 | return [$item['placePrediction']['placeId'] => $item['placePrediction']['text']['text']]; 165 | }); 166 | 167 | return $searchResults->toArray(); 168 | } 169 | } else { 170 | if (! empty($result['predictions'])) { 171 | $searchResults = collect($result['predictions'])->mapWithKeys(function (array $item, int $key) { 172 | return [$item['place_id'] => $item['description']]; 173 | }); 174 | 175 | return $searchResults->toArray(); 176 | } 177 | } 178 | 179 | return []; 180 | } 181 | 182 | public function withFields(null|array|string|\Closure $fields): static 183 | { 184 | $this->withFields = $fields; 185 | 186 | return $this; 187 | } 188 | 189 | public function getWithFields(): ?array 190 | { 191 | if (empty($this->withFields)) { 192 | return [ 193 | Forms\Components\TextInput::make('address') 194 | ->extraInputAttributes([ 195 | 'data-google-field' => '{street_number} {route}, {sublocality_level_1}', 196 | ]), 197 | Forms\Components\TextInput::make('city') 198 | ->extraInputAttributes([ 199 | 'data-google-field' => 'locality', 200 | ]), 201 | Forms\Components\TextInput::make('country'), 202 | Forms\Components\TextInput::make('zip') 203 | ->extraInputAttributes([ 204 | 'data-google-field' => 'postal_code', 205 | ]), 206 | ]; 207 | } 208 | 209 | return $this->evaluate($this->withFields); 210 | } 211 | 212 | public function autocompleteFieldColumnSpan(int|array|string|\Closure $autocompleteFieldColumnSpan = 'full'): static 213 | { 214 | $this->autocompleteFieldColumnSpan = $autocompleteFieldColumnSpan; 215 | 216 | $this->params['autocompleteFieldColumnSpan'] = $autocompleteFieldColumnSpan; 217 | 218 | return $this; 219 | } 220 | 221 | public function getAutocompleteFieldColumnSpan(): int|array|string|null 222 | { 223 | return $this->evaluate($this->autocompleteFieldColumnSpan); 224 | } 225 | 226 | public function addressFieldsColumns(null|array|string|\Closure $addressFieldsColumns): static 227 | { 228 | $this->addressFieldsColumns = $addressFieldsColumns; 229 | 230 | return $this; 231 | } 232 | 233 | public function getAddressFieldsColumns(): ?array 234 | { 235 | if (empty($this->addressFieldsColumns)) { 236 | return [ 237 | 'default' => 1, 238 | 'sm' => 2, 239 | ]; 240 | } 241 | 242 | return $this->evaluate($this->addressFieldsColumns); 243 | } 244 | 245 | public function autocompleteSearchDebounce(int|\Closure $autocompleteSearchDebounce = 2000): static 246 | { 247 | $this->autocompleteSearchDebounce = $autocompleteSearchDebounce; 248 | 249 | $this->params['autocompleteSearchDebounce'] = $autocompleteSearchDebounce; 250 | 251 | return $this; 252 | } 253 | 254 | public function getAutocompleteSearchDebounce(): ?int 255 | { 256 | return $this->evaluate($this->autocompleteSearchDebounce); 257 | } 258 | 259 | public function autocompleteLabel(string|Closure|null $label): static 260 | { 261 | $this->autocompleteLabel = $label; 262 | 263 | return $this; 264 | } 265 | 266 | protected function getAutocompleteLabel(): string 267 | { 268 | return $this->evaluate($this->autocompleteLabel) 269 | ?: (__('filament-google-autocomplete-field::filament-google-autocomplete-field.autocomplete.label') 270 | ?: $this->getLabel()); 271 | } 272 | 273 | public function autocompleteName(string|Closure|null $name): static 274 | { 275 | $this->autocompleteName = $name; 276 | 277 | return $this; 278 | } 279 | 280 | protected function getAutocompleteName(): string 281 | { 282 | return $this->evaluate($this->autocompleteName) ?? 'google_autocomplete_'.$this->name; 283 | } 284 | 285 | public function autocompletePlaceholder(string|Closure|null $placeholder): static 286 | { 287 | $this->autocompletePlaceholder = $placeholder; 288 | 289 | return $this; 290 | } 291 | 292 | protected function getAutocompletePlaceholder(): string 293 | { 294 | return $this->evaluate($this->autocompletePlaceholder) 295 | ?: __('filament-google-autocomplete-field::filament-google-autocomplete-field.autocomplete.placeholder'); 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `filament-google-autocomplete-field` will be documented in this file. 4 | 5 | ## v4.0.6 - 2025-11-16 6 | 7 | ### What's Changed 8 | 9 | * Add localization to label and placeholder by @andreia in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/64 10 | 11 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v4.0.5...v4.0.6 12 | 13 | ## v1.0.21 - 2025-11-16 14 | 15 | ### What's Changed 16 | 17 | * Larastan fix by @andreia in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/63 18 | 19 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.20...v1.0.21 20 | 21 | ## v1.0.20 - 2025-11-15 22 | 23 | ### What's Changed 24 | 25 | * Add localization for autocomplete fields by @csh-tech in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/62 26 | 27 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.19...v1.0.20 28 | 29 | ## v4.0.5 - 2025-11-03 30 | 31 | ### What's Changed 32 | 33 | * Unset autocompleteFieldColumnSpan params on HasGooglePlaceApi by @trippo in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/59 34 | 35 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v4.0.4...v4.0.5 36 | 37 | ## v1.0.19 - 2025-11-03 38 | 39 | ### What's Changed 40 | 41 | * Adding Hebrew language by @csh-tech in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/61 42 | 43 | ### New Contributors 44 | 45 | * @csh-tech made their first contribution in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/61 46 | 47 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.18...v1.0.19 48 | 49 | ## v1.0.18 - 2025-10-17 50 | 51 | ### What's Changed 52 | 53 | * Update columnSpan return types by @andreia in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/57 54 | 55 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.17...v1.0.18 56 | 57 | ## v4.0.4 - 2025-10-17 58 | 59 | ### What's Changed 60 | 61 | * Add int|array to autocompleteFieldColumnSpan() by @andreia in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/56 62 | 63 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v4.0.3...v4.0.4 64 | 65 | ## v1.0.17 - 2025-10-17 66 | 67 | ### What's Changed 68 | 69 | * Add int|array types to columnSpan param by @trippo in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/54 70 | 71 | ### New Contributors 72 | 73 | * @trippo made their first contribution in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/54 74 | 75 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.16...v1.0.17 76 | 77 | ## v1.0.16 - 2025-09-09 78 | 79 | ### What's Changed 80 | 81 | * Undefined index 0 fix with Turkish localizations by @onursahindur in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/52 82 | 83 | ### New Contributors 84 | 85 | * @onursahindur made their first contribution in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/52 86 | 87 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.15...v1.0.16 88 | 89 | ## v4.0.3 - 2025-09-08 90 | 91 | ### What's Changed 92 | 93 | * Fix submit fields by @andreia in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/51 94 | 95 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v4.0.2...v4.0.3 96 | 97 | ## v4.0.2 - 2025-08-20 98 | 99 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v4.0.1...v4.0.2 100 | 101 | ## v1.0.15 - 2025-08-20 102 | 103 | ### What's Changed 104 | 105 | * Update GoogleAutocomplete field processing to handle Hidden components by @erchecho in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/39 106 | 107 | ### New Contributors 108 | 109 | * @erchecho made their first contribution in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/39 110 | 111 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.14...v1.0.15 112 | 113 | ## v4.0.1 - 2025-08-19 114 | 115 | ### What's Changed 116 | 117 | * Added getOptionLabelUsing method by @gladjanus43 in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/48 118 | 119 | ### New Contributors 120 | 121 | * @gladjanus43 made their first contribution in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/48 122 | 123 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v4.0.0...v4.0.1 124 | 125 | ## v1.0.14 - 2025-08-12 126 | 127 | ### What's Changed 128 | 129 | * Bump aglipanci/laravel-pint-action from 2.5 to 2.6 by @dependabot[bot] in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/38 130 | * Add Filament 4 installation instruction by @andreia in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/45 131 | 132 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.13...v1.0.14 133 | 134 | ## v4.0.0 - 2025-08-12 135 | 136 | ### What's Changed 137 | 138 | * Bump aglipanci/laravel-pint-action from 2.5 to 2.6 by @dependabot[bot] in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/38 139 | * Filament 4 upgrade by @andreia in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/44 140 | 141 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.13...v4.0.0 142 | 143 | ## v1.0.13 - 2025-05-16 144 | 145 | ### What's Changed 146 | 147 | * Bump dependabot/fetch-metadata from 2.3.0 to 2.4.0 by @dependabot in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/34 148 | * Allow the use of different form layouts by @andreia in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/35 149 | 150 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.12...v1.0.13 151 | 152 | ## v1.0.12 - 2025-04-04 153 | 154 | ### What's Changed 155 | 156 | * Reset autocomplete field when performing a new search by @AlexandreCConcept in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/32 157 | 158 | ### New Contributors 159 | 160 | * @AlexandreCConcept made their first contribution in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/32 161 | 162 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.11...v1.0.12 163 | 164 | ## v1.0.11 - 2025-03-15 165 | 166 | ### What's Changed 167 | 168 | * Add placeholder by @andreia in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/25 169 | 170 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.10...v1.0.11 171 | 172 | ## v1.0.10 - 2025-03-10 173 | 174 | ### What's Changed 175 | 176 | * Add Laravel 12 compatibility by @andreia in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/26 177 | 178 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.9...v1.0.10 179 | 180 | ## v1.0.9 - 2025-02-17 181 | 182 | ### What's Changed 183 | 184 | * Add language in Place Details by @andreia in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/19 185 | 186 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.8...v1.0.9 187 | 188 | ## v1.0.8 - 2025-02-10 189 | 190 | ### What's Changed 191 | 192 | * Bump dependabot/fetch-metadata from 2.2.0 to 2.3.0 by @dependabot in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/13 193 | * Bump aglipanci/laravel-pint-action from 2.4 to 2.5 by @dependabot in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/15 194 | * Method for customising the label of the Google autocomplete select field by @alexb34n in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/17 195 | 196 | ### New Contributors 197 | 198 | * @alexb34n made their first contribution in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/17 199 | 200 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.7...v1.0.8 201 | 202 | ## v1.0.7 - 2025-01-13 203 | 204 | ### What's Changed 205 | 206 | * Allow multiple autocomplete instances by @andreia in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/12 207 | 208 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.6...v1.0.7 209 | 210 | ## v1.0.6 - 2025-01-05 211 | 212 | ### What's Changed 213 | 214 | * Add support to Google Places API (New) by @andreia in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/11 215 | 216 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.5...v1.0.6 217 | 218 | ## v1.0.5 - 2024-12-30 219 | 220 | ### What's Changed 221 | 222 | * Call afterStateUpdated hook on value change by @JacobDelcroix in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/10 223 | 224 | ### New Contributors 225 | 226 | * @JacobDelcroix made their first contribution in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/10 227 | 228 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.4...v1.0.5 229 | 230 | ## v1.0.4 - 2024-12-02 231 | 232 | ### What's Changed 233 | 234 | * Added italian language support by @matteo3105wbl in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/7 235 | 236 | ### New Contributors 237 | 238 | * @matteo3105wbl made their first contribution in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/7 239 | 240 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.3...v1.0.4 241 | 242 | ## v1.0.3 - 2024-10-27 243 | 244 | ### What's Changed 245 | 246 | * Fixes error thrown if administrative_area_level_2 is missing in search result by @bcash in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/6 247 | 248 | ### New Contributors 249 | 250 | * @bcash made their first contribution in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/6 251 | 252 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.2...v1.0.3 253 | 254 | ## v1.0.2 - 2024-08-05 255 | 256 | ### What's Changed 257 | 258 | * Prevent google_autocomplete select from being dehydrated by @andreia in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/5 259 | 260 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.1...v1.0.2 261 | 262 | ## v1.0.1 - 2024-07-25 263 | 264 | ### What's Changed 265 | 266 | * Fix empty state on google autocomplete select by @andreia in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/3 267 | 268 | ### New Contributors 269 | 270 | * @andreia made their first contribution in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/3 271 | 272 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/compare/v1.0.0...v1.0.1 273 | 274 | ## v1.0.0 - 2024-07-14 275 | 276 | ### What's Changed 277 | 278 | * Bump dependabot/fetch-metadata from 2.1.0 to 2.2.0 by @dependabot in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/1 279 | 280 | ### New Contributors 281 | 282 | * @dependabot made their first contribution in https://github.com/TappNetwork/filament-google-autocomplete-field/pull/1 283 | 284 | **Full Changelog**: https://github.com/TappNetwork/filament-google-autocomplete-field/commits/v1.0.0 285 | -------------------------------------------------------------------------------- /src/Concerns/HasGooglePlaceApi.php: -------------------------------------------------------------------------------- 1 | [ 24 | 'longText' => 'longText', 25 | 'shortText' => 'shortText', 26 | 'googleAddressExtraFieldNames' => [ 27 | 'id', 28 | 'nationalPhoneNumber', 29 | 'internationalPhoneNumber', 30 | 'formattedAddress', 31 | 'displayName', 32 | 'websiteUri', 33 | ], 34 | ], 35 | 'originalApi' => [ 36 | 'longText' => 'long_name', 37 | 'shortText' => 'short_name', 38 | 'googleAddressExtraFieldNames' => [ 39 | 'place_id', 40 | 'formatted_phone_number', 41 | 'international_phone_number', 42 | 'formatted_address', 43 | 'name', 44 | 'website', 45 | ], 46 | ], 47 | ]; 48 | 49 | protected array $currentApiNamingConventions = []; 50 | 51 | protected bool|Closure $placesApiNew = false; 52 | 53 | protected bool|Closure $includePureServiceAreaBusinesses = false; 54 | 55 | protected string|array|Closure|null $countries = null; 56 | 57 | protected array|Closure|null $includedRegionCodes = null; 58 | 59 | protected string|Closure|null $language = null; 60 | 61 | protected string|Closure|null $location = null; 62 | 63 | protected string|array|Closure|null $locationBias = null; 64 | 65 | protected string|Closure|null $locationRestriction = null; 66 | 67 | protected int|Closure|null $offset = null; 68 | 69 | protected string|Closure|null $origin = null; 70 | 71 | protected int|Closure|null $radius = null; 72 | 73 | protected string|Closure|null $region = null; 74 | 75 | protected string|Closure|null $sessionToken = null; 76 | 77 | protected string|array|Closure|null $placeTypes = null; 78 | 79 | protected function getPlaceAutocomplete($search) 80 | { 81 | $this->setGoogleApi(); 82 | 83 | if ($this->placesApiNew) { 84 | return $this->googlePlaces->autocomplete($search, false, ['*'], $this->params); 85 | } 86 | 87 | return $this->googlePlaces->placeAutocomplete($search, $this->params); 88 | } 89 | 90 | protected function getPlace(string $placeId) 91 | { 92 | $this->setGoogleApi(); 93 | 94 | $detailParams = []; 95 | 96 | if ($this->placesApiNew) { 97 | $detailParams['languageCode'] = $this->params['languageCode'] ?? null; 98 | 99 | return $this->googlePlaces->placeDetails($placeId, ['*'], $detailParams); 100 | } 101 | 102 | $detailParams['language'] = $this->params['language'] ?? null; 103 | 104 | return $this->googlePlaces->placeDetails($placeId, $detailParams); 105 | } 106 | 107 | protected function getFormattedApiResults($data): array 108 | { 109 | $response = $data->collect(); 110 | 111 | if ($this->placesApiNew) { 112 | $addressComponents = $response['addressComponents']; 113 | 114 | $latLngFields = [ 115 | 'latitude' => [ 116 | 'long_name' => $response['location']['latitude'], 117 | 'short_name' => $response['location']['latitude'], 118 | ], 119 | 'longitude' => [ 120 | 'long_name' => $response['location']['longitude'], 121 | 'short_name' => $response['location']['longitude'], 122 | ], 123 | ]; 124 | 125 | $extraFields = $response->toArray(); 126 | } else { 127 | $result = $response['result']; 128 | 129 | $addressComponents = $result['address_components']; 130 | 131 | $latLngFields = $result['geometry']['location']; 132 | 133 | $latLngFields = [ 134 | 'latitude' => [ 135 | 'long_name' => $latLngFields['lat'], 136 | 'short_name' => $latLngFields['lat'], 137 | ], 138 | 'longitude' => [ 139 | 'long_name' => $latLngFields['lng'], 140 | 'short_name' => $latLngFields['lng'], 141 | ], 142 | ]; 143 | 144 | $extraFields = $result; 145 | } 146 | 147 | // array map with keys 148 | $addressFields = array_merge(...array_map(function ($key, $item) { 149 | if (! isset($item['types']) || empty($item['types']) || ! isset($item['types'][0])) { 150 | return []; 151 | } 152 | 153 | return [ 154 | $item['types'][0] => [ 155 | 'long_name' => $item[$this->currentApiNamingConventions['longText']], 156 | 'short_name' => $item[$this->currentApiNamingConventions['shortText']], 157 | ], 158 | ]; 159 | }, array_keys($addressComponents), $addressComponents)); 160 | 161 | // array map with keys 162 | $extraFields = array_merge(...array_map(function ($key, $item) { 163 | if (in_array($key, $this->currentApiNamingConventions['googleAddressExtraFieldNames'])) { 164 | $item = $key === 'displayName' ? $item['text'] : $item; 165 | 166 | return [ 167 | $key => [ 168 | 'long_name' => $item, 169 | 'short_name' => $item, 170 | ], 171 | ]; 172 | } else { 173 | return []; 174 | } 175 | }, array_keys($extraFields), $extraFields)); 176 | 177 | return array_merge($addressFields, $extraFields, $latLngFields); 178 | } 179 | 180 | public function placesApiNew(bool|Closure $placesApiNew = true): static 181 | { 182 | $this->placesApiNew = $placesApiNew; 183 | 184 | return $this; 185 | } 186 | 187 | public function getPlacesApiNew(): bool 188 | { 189 | return $this->evaluate($this->placesApiNew); 190 | } 191 | 192 | public function includePureServiceAreaBusinesses(bool|Closure $includePureServiceAreaBusinesses = false): static 193 | { 194 | $this->params['includePureServiceAreaBusinesses'] = $includePureServiceAreaBusinesses; 195 | 196 | $this->includePureServiceAreaBusinesses = $includePureServiceAreaBusinesses; 197 | 198 | return $this; 199 | } 200 | 201 | public function getIncludePureServiceAreaBusinesses(): bool 202 | { 203 | return $this->evaluate($this->includePureServiceAreaBusinesses); 204 | } 205 | 206 | protected function setGoogleApi() 207 | { 208 | $googleClass = 'SKAgarwal\GoogleApi\Places\GooglePlaces'; 209 | 210 | $this->currentApiNamingConventions = $this->apiNamingConventions['originalApi']; 211 | 212 | if ($this->placesApiNew) { 213 | $googleClass = 'SKAgarwal\GoogleApi\PlacesNew\GooglePlaces'; 214 | 215 | $this->currentApiNamingConventions = $this->apiNamingConventions['newApi']; 216 | } 217 | 218 | $this->googlePlaces = $googleClass::make( 219 | key: config('filament-google-autocomplete-field.api-key'), 220 | verifySSL: config('filament-google-autocomplete-field.verify-ssl'), 221 | throwOnErrors: config('filament-google-autocomplete-field.throw-on-errors'), 222 | ); 223 | } 224 | 225 | public function countries(array|string|Closure|null $countries): static 226 | { 227 | $countries = Arr::wrap($countries); 228 | 229 | $this->countries = $countries; 230 | 231 | $this->params['components'] = $this->getFormattedCountries($countries); 232 | 233 | return $this; 234 | } 235 | 236 | public function getCountries(): ?string 237 | { 238 | return $this->evaluate($this->countries); 239 | } 240 | 241 | public function includedRegionCodes(array|Closure|null $includedRegionCodes): static 242 | { 243 | $includedRegionCodes = Arr::wrap($includedRegionCodes); 244 | 245 | $this->includedRegionCodes = $includedRegionCodes; 246 | 247 | $this->params['includedRegionCodes'] = $includedRegionCodes; 248 | 249 | return $this; 250 | } 251 | 252 | public function getIncludedRegionCodes(): ?array 253 | { 254 | return $this->evaluate($this->includedRegionCodes); 255 | } 256 | 257 | public function language(string|Closure|null $language): static 258 | { 259 | $this->language = $language; 260 | 261 | if ($this->placesApiNew) { 262 | $this->params['languageCode'] = $language; 263 | } else { 264 | $this->params['language'] = $language; 265 | } 266 | 267 | return $this; 268 | } 269 | 270 | public function getLanguage(): ?string 271 | { 272 | return $this->evaluate($this->language); 273 | } 274 | 275 | public function location(string|Closure|null $location): static 276 | { 277 | $this->location = $location; 278 | 279 | $this->params['location'] = $location; 280 | 281 | return $this; 282 | } 283 | 284 | public function getLocation(): ?string 285 | { 286 | return $this->evaluate($this->location); 287 | } 288 | 289 | public function locationBias(string|array|Closure|null $locationBias): static 290 | { 291 | $this->locationBias = $locationBias; 292 | 293 | if ($this->placesApiNew) { 294 | $this->params['locationBias'] = $locationBias; 295 | } else { 296 | $this->params['locationbias'] = $locationBias; 297 | } 298 | 299 | return $this; 300 | } 301 | 302 | public function getLocationBias(): null|string|array 303 | { 304 | return $this->evaluate($this->locationBias); 305 | } 306 | 307 | public function locationRestriction(string|Closure|null $locationRestriction): static 308 | { 309 | $this->locationRestriction = $locationRestriction; 310 | 311 | if ($this->placesApiNew) { 312 | $this->params['locationRestriction'] = $locationRestriction; 313 | } else { 314 | $this->params['locationrestriction'] = $locationRestriction; 315 | } 316 | 317 | return $this; 318 | } 319 | 320 | public function getLocationRestriction(): ?string 321 | { 322 | return $this->evaluate($this->locationRestriction); 323 | } 324 | 325 | public function offset(int|Closure|null $offset): static 326 | { 327 | $this->offset = $offset; 328 | 329 | if ($this->placesApiNew) { 330 | $this->params['inputOffset'] = $offset; 331 | } else { 332 | $this->params['offset'] = $offset; 333 | } 334 | 335 | return $this; 336 | } 337 | 338 | public function getOffset(): ?int 339 | { 340 | return $this->evaluate($this->offset); 341 | } 342 | 343 | public function origin(string|Closure|null $origin): static 344 | { 345 | $this->origin = $origin; 346 | 347 | $this->params['origin'] = $origin; 348 | 349 | return $this; 350 | } 351 | 352 | public function getOrigin(): ?string 353 | { 354 | return $this->evaluate($this->origin); 355 | } 356 | 357 | public function radius(int|Closure|null $radius): static 358 | { 359 | $this->radius = $radius; 360 | 361 | $this->params['radius'] = $radius; 362 | 363 | return $this; 364 | } 365 | 366 | public function getRadius(): ?int 367 | { 368 | return $this->evaluate($this->radius); 369 | } 370 | 371 | public function region(string|Closure|null $region): static 372 | { 373 | $this->region = $region; 374 | 375 | if ($this->placesApiNew) { 376 | $this->params['regionCode'] = $region; 377 | } else { 378 | $this->params['region'] = $region; 379 | } 380 | 381 | return $this; 382 | } 383 | 384 | public function getRegion(): ?string 385 | { 386 | return $this->evaluate($this->region); 387 | } 388 | 389 | public function sessionToken(string|Closure|null $sessionToken): static 390 | { 391 | $this->sessionToken = $sessionToken; 392 | 393 | if ($this->placesApiNew) { 394 | $this->params['sessionToken'] = $sessionToken; 395 | } else { 396 | $this->params['sessiontoken'] = $sessionToken; 397 | } 398 | 399 | return $this; 400 | } 401 | 402 | public function getSessionToken(): ?string 403 | { 404 | return $this->evaluate($this->sessionToken); 405 | } 406 | 407 | public function placeTypes(array|string|Closure|null $placeTypes): static 408 | { 409 | $placeTypes = Arr::wrap($placeTypes); 410 | 411 | $this->placeTypes = $placeTypes; 412 | 413 | if ($this->placesApiNew) { 414 | $this->params['includedPrimaryTypes'] = $placeTypes; 415 | } else { 416 | $this->params['types'] = $this->getFormattedPlaceTypes($placeTypes); 417 | } 418 | 419 | return $this; 420 | } 421 | 422 | public function getPlaceTypes(): ?string 423 | { 424 | return $this->evaluate($this->placeTypes); 425 | } 426 | } 427 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Filament Google Autcomplete Field 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/tapp/filament-google-autocomplete-field.svg?style=flat-square)](https://packagist.org/packages/tapp/filament-google-autocomplete-field) 4 | ![GitHub Tests Action Status](https://github.com/TappNetwork/filament-google-autocomplete-field/actions/workflows/run-tests.yml/badge.svg) 5 | ![GitHub Code Style Action Status](https://github.com/TappNetwork/filament-google-autocomplete-field/actions/workflows/fix-php-code-style-issues.yml/badge.svg) 6 | [![Total Downloads](https://img.shields.io/packagist/dt/tapp/filament-google-autocomplete-field.svg?style=flat-square)](https://packagist.org/packages/tapp/filament-google-autocomplete-field) 7 | 8 | This plugin provides an address autocomplete using [Google Place autocomplete API](https://developers.google.com/maps/documentation/places/web-service/autocomplete), with fully customizable address fields. 9 | 10 | > [!NOTE] 11 | > The [Google Places API package](https://github.com/SachinAgarwal1337/google-places-api) is used to make API requests to Google Places. 12 | 13 | ## Version Compatibility 14 | 15 | Filament | Filament Google Autocomplete Field 16 | :---------|:---------------------------------- 17 | 3.x | 1.x 18 | 4.x | 4.x 19 | 20 | ## Installation 21 | 22 | You can install the package via Composer: 23 | 24 | ### For Filament 3 25 | 26 | ```bash 27 | composer require tapp/filament-google-autocomplete-field:"^1.0" 28 | ``` 29 | 30 | ### For Filament 4 31 | 32 | ```bash 33 | composer require tapp/filament-google-autocomplete-field:"^4.0" 34 | ``` 35 | 36 | You can publish the config file with: 37 | 38 | ```bash 39 | php artisan vendor:publish --tag="filament-google-autocomplete-field-config" 40 | ``` 41 | 42 | This is the contents of the published config file: 43 | 44 | ```php 45 | return [ 46 | 47 | 'api-key' => env('GOOGLE_PLACES_API_KEY', ''), 48 | 'verify-ssl' => true, 49 | 'throw-on-errors' => false, 50 | 51 | ]; 52 | ``` 53 | 54 | Optionally, you can publish the translation files with: 55 | 56 | ```bash 57 | php artisan vendor:publish --tag="filament-google-autocomplete-field-translations" 58 | ``` 59 | 60 | ## Setup 61 | 62 | On [Google console](https://console.cloud.google.com/apis/dashboard), create an application and enable the Places API. 63 | 64 | 1. Click on "ENABLE APIS AND SERVICES" 65 | 2. Search for "Places api" 66 | 3. Click to enable it 67 | 4. Get the API key 68 | 69 | In your Laravel application, add the Google API key to `GOOGLE_PLACES_API_KEY` in your `.env` file: 70 | 71 | ```php 72 | GOOGLE_PLACES_API_KEY=your_google_place_api_key_here 73 | ``` 74 | 75 | ## Appareance 76 | 77 | ![Filament Google Autcomplete Field](https://raw.githubusercontent.com/TappNetwork/filament-google-autocomplete-field/main/docs/autocomplete02.png) 78 | 79 | ![Filament Google Autcomplete Field](https://raw.githubusercontent.com/TappNetwork/filament-google-autocomplete-field/main/docs/autocomplete03.png) 80 | 81 | ![Filament Google Autcomplete Field](https://raw.githubusercontent.com/TappNetwork/filament-google-autocomplete-field/main/docs/autocomplete04.png) 82 | 83 | ![Filament Google Autcomplete Field](https://raw.githubusercontent.com/TappNetwork/filament-google-autocomplete-field/main/docs/autocomplete05.png) 84 | 85 | ![Filament Google Autcomplete Field](https://raw.githubusercontent.com/TappNetwork/filament-google-autocomplete-field/main/docs/autocomplete06.png) 86 | 87 | ## Usage 88 | 89 | Add the `GoogleAutocomplete` field to your form: 90 | 91 | ```php 92 | use Tapp\FilamentGoogleAutocomplete\Forms\Components\GoogleAutocomplete; 93 | 94 | GoogleAutocomplete::make('google_search'), 95 | ``` 96 | 97 | This will use the default address fields and Google API options. You can also customize the address fields and Google Place API options. See all the options available on [`Available options`](#available-options) item below. For example: 98 | 99 | ```php 100 | use Tapp\FilamentGoogleAutocomplete\Forms\Components\GoogleAutocomplete; 101 | 102 | GoogleAutocomplete::make('google_search') 103 | ->label('Google look-up') 104 | ->countries([ 105 | 'US', 106 | 'AU', 107 | ]) 108 | ->language('pt-BR') 109 | ->withFields([ 110 | Forms\Components\TextInput::make('address') 111 | ->extraInputAttributes([ 112 | 'data-google-field' => '{street_number} {route}, {sublocality_level_1}', 113 | ]), 114 | Forms\Components\TextInput::make('country'), 115 | Forms\Components\TextInput::make('coordinates') 116 | ->extraInputAttributes([ 117 | 'data-google-field' => '{latitude}, {longitude}', 118 | ]), 119 | ]), 120 | ``` 121 | 122 | ### Using form layouts 123 | 124 | The Google autocomplete fields can be wrapped in a Form layout like `Fieldset` or `Section`: 125 | 126 | ```php 127 | Forms\Components\Fieldset::make('Google Search') 128 | ->schema([ 129 | GoogleAutocomplete::make('google_search_field') 130 | // ... 131 | ]), 132 | ``` 133 | 134 | ![Fieldset Layout](https://raw.githubusercontent.com/TappNetwork/filament-google-autocomplete-field/main/docs/fieldset_layout.png) 135 | 136 | ```php 137 | Forms\Components\Section::make('Google Search') 138 | ->schema([ 139 | GoogleAutocomplete::make('google_search_field') 140 | // ... 141 | ]), 142 | ``` 143 | 144 | ![Section Layout](https://raw.githubusercontent.com/TappNetwork/filament-google-autocomplete-field/main/docs/section_layout.png) 145 | 146 | ## Places API (original) and Places API (New) 147 | 148 | Both the **[Places API (original)](https://developers.google.com/maps/documentation/places/web-service/autocomplete)** and the **[Places API (New)](https://developers.google.com/maps/documentation/places/web-service/place-autocomplete)** are supported. 149 | By default, the Places API (original) it's used. To use the Places API (New) instead, add the `->placesApiNew()` method, like so: 150 | 151 | ```php 152 | GoogleAutocomplete::make('google_search') 153 | ->placesApiNew() 154 | ``` 155 | 156 | ## Available Options 157 | 158 | ### Autocompleted Fields 159 | 160 | You can use the `withFields` method to define the fields that will be autocompleted. 161 | 162 | By default the following fields are set if this method isn't provided: 163 | 164 | ```php 165 | Forms\Components\TextInput::make('address') 166 | ->extraInputAttributes([ 167 | 'data-google-field' => '{street_number} {route}, {sublocality_level_1}', 168 | ]), 169 | Forms\Components\TextInput::make('city') 170 | ->extraInputAttributes([ 171 | 'data-google-field' => 'locality', 172 | ]), 173 | Forms\Components\TextInput::make('country'), 174 | Forms\Components\TextInput::make('zip') 175 | ->extraInputAttributes([ 176 | 'data-google-field' => 'postal_code', 177 | ]), 178 | ``` 179 | 180 | You can override these default fields by passing an array of Filament form fields to `withFields` method: 181 | 182 | ```php 183 | GoogleAutocompleteFields::make('google_search') 184 | ->withFields([ 185 | Forms\Components\TextInput::make('address') 186 | ->extraInputAttributes([ 187 | 'data-google-field' => '{street_number} {route}, {sublocality_level_1}', 188 | ]), 189 | Forms\Components\TextInput::make('city') 190 | ->extraInputAttributes([ 191 | 'data-google-field' => 'locality', 192 | ]), 193 | ]), 194 | ``` 195 | 196 | #### Combining Fields 197 | 198 | You can combine multiple fields returned by Google API in one field using curly braces `{}` to wrap the fields in `'data-google-field'` extra input attribute. For example, the `address` field below will contain the `street_number`, `route`, and `sublocality_level_1` and the `coordinates` field will contain the `latitude` and `longitude` fields: 199 | 200 | ```php 201 | Forms\Components\TextInput::make('address') 202 | ->extraInputAttributes([ 203 | 'data-google-field' => '{street_number} {route}, {sublocality_level_1}', 204 | ]), 205 | Forms\Components\TextInput::make('coordinates') 206 | ->extraInputAttributes([ 207 | 'data-google-field' => '{latitude},{longitude}', 208 | ]), 209 | ``` 210 | 211 | #### Field Name 212 | 213 | If your database field have a different name than the Google field (for example you DB field is `zip` and you want to use the Google's `postal_code` value returned by API), you can tie the API field to the DB field by passing your DB field name to `'data-google-field'` on `extraInputAttributes` method like so: 214 | 215 | ```php 216 | Forms\Components\TextInput::make('zip') 217 | ->extraInputAttributes([ 218 | 'data-google-field' => 'postal_code', 219 | ]) 220 | ``` 221 | 222 | These are the names of the Google metadata fields available to use: 223 | 224 | ``` 225 | street_number, 226 | route, 227 | locality, 228 | sublocality_level_1, 229 | administrative_area_level_2, 230 | administrative_area_level_1, 231 | country, 232 | postal_code, 233 | place_id, 234 | formatted_address, 235 | formatted_phone_number, 236 | international_phone_number, 237 | name, 238 | website, 239 | latitude, 240 | longitude, 241 | ``` 242 | 243 | #### long_name and short_name 244 | 245 | Google's Places API returns `long_name` and `short_name` values for address fields. You can choose which one to display by passing it to the `'data-google-value'` on `extraInputAttributes` method: 246 | 247 | ```php 248 | Forms\Components\TextInput::make('country') 249 | ->extraInputAttributes([ 250 | 'data-google-value' => 'short_name', 251 | ]) 252 | ``` 253 | 254 | E.g. of `long_name` and `short_name` data returned by Google's API: 255 | 256 | ```php 257 | "street_number" => [ 258 | "long_name" => "1535" 259 | "short_name" => "1535" 260 | ] 261 | "route" => [ 262 | "long_name" => "Broadway" 263 | "short_name" => "Broadway" 264 | ] 265 | "locality" => [ 266 | "long_name" => "New York" 267 | "short_name" => "New York" 268 | ] 269 | "sublocality_level_1" => [ 270 | "long_name" => "Manhattan" 271 | "short_name" => "Manhattan" 272 | ] 273 | "administrative_area_level_2" => [ 274 | "long_name" => "New York County" 275 | "short_name" => "New York County" 276 | ] 277 | "administrative_area_level_1" => [ 278 | "long_name" => "New York" 279 | "short_name" => "NY" 280 | ] 281 | "country" => [ 282 | "long_name" => "United States" 283 | "short_name" => "US" 284 | ] 285 | "postal_code" => [ 286 | "long_name" => "10036" 287 | "short_name" => "10036" 288 | ] 289 | ``` 290 | 291 | ### Autocomplete Field Column Span 292 | 293 | The default column span for autcomplete select field is `'full'`. You can define other value (same as supported by Filament's `columnSpan()`) using the `autocompleteFieldColumnSpan` method: 294 | 295 | ```php 296 | GoogleAutocomplete::make('google_search') 297 | ->autocompleteFieldColumnSpan(1) 298 | ``` 299 | 300 | ### Autocomplete Field Search Debounce 301 | 302 | The default search debounce is 2 seconds to avoid too many requests to Google Places API. You can define other value using `autocompleteSearchDebounce` method: 303 | 304 | ```php 305 | GoogleAutocomplete::make('google_search') 306 | ->autocompleteSearchDebounce(1000) // 1 second 307 | ``` 308 | 309 | ### Autocomplete Label 310 | 311 | The label of the autocomplete select field can be modified using the `->autocompleteLabel()` method: 312 | 313 | ```php 314 | GoogleAutocomplete::make('google_search') 315 | ->autocompleteLabel('Select a location') 316 | ``` 317 | 318 | ### Autocomplete Placeholder 319 | 320 | The placeholder can be modified using the `->autocompletePlaceholder()` method: 321 | 322 | ```php 323 | GoogleAutocomplete::make('google_search') 324 | ->autocompletePlaceholder('Select a location') 325 | ``` 326 | 327 | Example with modified `label`, `autocompleteLabel`, and `autocompletePlaceholder`: 328 | 329 | ```php 330 | GoogleAutocomplete::make('google_search') 331 | ->autocompleteLabel('Select a location') 332 | ->autocompletePlaceholder('Click here to search') 333 | ->label('Searching on Google...') 334 | ->countries([ 335 | 'us', 336 | 'au', 337 | ]) 338 | ->placeTypes([ 339 | 'book_store', 340 | 'cafe', 341 | ]) 342 | ->withFields([ 343 | Forms\Components\TextInput::make('address') 344 | ->extraInputAttributes([ 345 | 'data-google-field' => '{street_number} {route}, {sublocality_level_1}', 346 | ]), 347 | Forms\Components\TextInput::make('city') 348 | ->extraInputAttributes([ 349 | 'data-google-field' => 'locality', 350 | ]), 351 | ]), 352 | ``` 353 | 354 | ![Example with modified label, autocompleteLabel, and autocompletePlaceholder](https://raw.githubusercontent.com/TappNetwork/filament-google-autocomplete-field/main/docs/label_placeholder.jpg) 355 | 356 | ## Google API Options 357 | 358 | These following **Google API options** can be passed to the `GoogleAutocomplete` field: 359 | 360 | ### OPTIONS FOR BOTH APIs 361 | 362 | ### PlaceTypes 363 | 364 | Restrict the results to be of a certain type. Pass the [available types](https://developers.google.com/maps/documentation/places/web-service/supported_types) as an array: 365 | 366 | ```php 367 | GoogleAutocomplete::make('google_search') 368 | ->placeTypes([ 369 | 'lodging', 370 | 'book_store', 371 | 'florist', 372 | ]) 373 | ``` 374 | 375 | Please refer to the [Google Places API original documentation](https://developers.google.com/maps/documentation/places/web-service/autocomplete#types) and [Google Places API New documentation](https://developers.google.com/maps/documentation/places/web-service/place-autocomplete#includedPrimaryTypes) to a detailed description of this option. 376 | 377 | ### Language 378 | 379 | The language which results should be returned. These are the [supported language codes](https://developers.google.com/maps/faq#languagesupport). 380 | 381 | ```php 382 | GoogleAutocomplete::make('google_search') 383 | ->language('pt-BR') 384 | ``` 385 | 386 | ### Offset 387 | 388 | The position, in the input term, of the last character that the service uses to match predictions. For example, if the input is Google and the offset is 3, the service will match on Goo. 389 | 390 | ```php 391 | GoogleAutocomplete::make('google_search') 392 | ->offset(5) 393 | ``` 394 | 395 | ### LocationBias 396 | 397 | Prefer results in a specified area, by specifying either a radius plus lat/lng, or two lat/lng pairs representing the points of a rectangle. If this parameter is not specified, the API uses IP address biasing by default. 398 | 399 | Please refer to the [Google Places API original documentation](https://developers.google.com/maps/documentation/places/web-service/autocomplete#locationbias) and [Google Places API New](https://developers.google.com/maps/documentation/places/web-service/place-autocomplete#location-bias-restriction) to a detailed description of this option. 400 | 401 | ```php 402 | GoogleAutocomplete::make('google_search') 403 | ->locationBias( 404 | [ 405 | "circle" => [ 406 | "center" => [ 407 | "latitude" => 37.7937, 408 | "longitude" => -122.3965 409 | ], 410 | "radius" => 500.0 411 | ] 412 | ] 413 | ) 414 | ``` 415 | 416 | ### LocationRestriction 417 | 418 | Restrict results to a specified area, by specifying either a radius plus lat/lng, or two lat/lng pairs representing the points of a rectangle. 419 | 420 | Please refer to the [Google Places API original documentation](https://developers.google.com/maps/documentation/places/web-service/autocomplete#locationrestriction) and [Google Places API New](https://developers.google.com/maps/documentation/places/web-service/place-autocomplete#location-bias-restriction) to a detailed description of this option. 421 | 422 | ### Origin 423 | 424 | The origin point as `latitude,longitude` from which to calculate straight-line distance to the destination specified. 425 | 426 | Please refer to the [Google documentation](https://developers.google.com/maps/documentation/places/web-service/autocomplete#origin) to a detailed description of this option. 427 | 428 | ```php 429 | GoogleAutocomplete::make('google_search') 430 | ->origin(40.7585862,-73.9858202) 431 | ``` 432 | 433 | ### Region 434 | 435 | The region code used to format the response, specified as a [country code top-level domain (ccTLD)](https://en.wikipedia.org/wiki/List_of_Internet_top-level_domains#Country_code_top-level_domains) two-character value. 436 | 437 | ```php 438 | GoogleAutocomplete::make('google_search') 439 | ->region('uk') 440 | ``` 441 | 442 | ### SessionToken 443 | 444 | Random string which identifies an autocomplete session for billing purposes. 445 | 446 | Please refer to the [Google documentation](https://developers.google.com/maps/documentation/places/web-service/autocomplete#sessiontoken) to a detailed description of this option. 447 | 448 | 449 | ### OPTIONS ONLY FOR PLACES API (ORIGINAL) 450 | 451 | ### Countries 452 | 453 | Add the `countries` method to restrict the countries that should be used for autocomplete search. 454 | 455 | The countries must be passed as a two character ISO 3166-1 Alpha-2 compatible country code. You can find the country codes available at [Wikipedia: List of ISO 3166 country codes](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). 456 | 457 | ```php 458 | GoogleAutocomplete::make('google_search') 459 | ->countries([ 460 | 'US', 461 | 'AU', 462 | ]) 463 | ``` 464 | 465 | ### Location 466 | 467 | The point around which to retrieve place information as `latitude,longitude`. 468 | 469 | Please refer to the [Google documentation](https://developers.google.com/maps/documentation/places/web-service/autocomplete#location) to a detailed description of this option. 470 | 471 | ```php 472 | GoogleAutocomplete::make('google_search') 473 | ->location(40.7585862,-73.9858202) 474 | ``` 475 | 476 | ### Radius 477 | 478 | The distance in meters within which to return place results. 479 | 480 | Please refer to the [Google documentation](https://developers.google.com/maps/documentation/places/web-service/autocomplete#radius) to a detailed description of this option. 481 | 482 | ```php 483 | GoogleAutocomplete::make('google_search') 484 | ->radius(10) 485 | ``` 486 | 487 | 488 | ### OPTIONS ONLY FOR PLACES API (NEW) 489 | 490 | ### IncludePureServiceAreaBusinesses 491 | 492 | `true` - includes businesses that visit or deliver to customers directly, but don't have a physical business location. 493 | `false` - returns only businesses with a physical business location. 494 | 495 | ```php 496 | GoogleAutocomplete::make('google_search') 497 | ->includePureServiceAreaBusinesses(true) 498 | ``` 499 | 500 | ### IncludedRegionCodes 501 | 502 | Only include results from the list of specified regions, specified as an array of up to 15 ccTLD ("top-level domain") two-character values. When omitted, no restrictions are applied to the response. 503 | 504 | ```php 505 | GoogleAutocomplete::make('google_search') 506 | ->includedRegionCodes([ 507 | "de", 508 | "fr", 509 | ]) 510 | ``` 511 | 512 | 513 | ## Testing 514 | 515 | ```bash 516 | composer test 517 | ``` 518 | 519 | ## Changelog 520 | 521 | Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently. 522 | 523 | ## Contributing 524 | 525 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 526 | 527 | ## Security Vulnerabilities 528 | 529 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 530 | 531 | ## Credits 532 | 533 | - [Tapp Network](https://github.com/TappNetwork) 534 | - [All Contributors](../../contributors) 535 | 536 | ## License 537 | 538 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 539 | --------------------------------------------------------------------------------