CRUD icon indicating copy to clipboard operation
CRUD copied to clipboard

[4.1][Package / Custom Field] Input Address with Google API / Google Maps

Open M4rk3tt0 opened this issue 7 years ago • 8 comments

Summary

Creates an address form composed by:

  • an autocomplete field based on Google Places API
  • several other fields, choosen by the user, that will contain the components of the address

The fields will be filled automatically

Preview

address

Usage

$this->crud->addField([
            'name'              => 'address',
            'label'             => 'Indirizzo',
            'type'              => 'address_form_google',
            'google_api_key'    => env('GOOGLE_API_KEY'),

            'components' =>  [
                'COMPONENT' => [   
                    'name'  => 'address_line_1',
                    'label' => 'Via',
                    'type'  => 'long_name', // Optional
                ],
                // Other components
            ],
        ]);

This field needs a Google API Key that can be retrived here

The components that can be used are:

  • 'route'
  • 'street_number'
  • 'postal_code'
  • 'locality'
  • 'administrative_area_level_1'
  • 'administrative_area_level_2'
  • 'country'

so a complete field would look like this:

$this->crud->addField([
            'name'              => 'address',
            'label'             => 'Indirizzo',
            'type'              => 'address_form_google',
            'google_api_key'    => env('GOOGLE_API_KEY'),

            'components' =>  [
                'route' => [   
                    'name'  => 'address_line_1',
                    'label' => 'Via',
                    'type'  => 'long_name',
                ],
                'street_number' => [   
                    'name'  => 'address_line_2',
                    'label' => 'Civico',
                    'type'  => 'short_name',
                ],
                'postal_code' => [   
                    'name'  => 'postal_code',
                    'label' => 'CAP',
                    'type'  => 'short_name',
                ],
                'locality' => [  
                    'name'  => 'city',
                    'label' => 'Città',
                    'type'  => 'long_name',
                ],    
                'administrative_area_level_1' => [    
                    'name'  => 'region',
                    'label' => 'Regione',
                    'type'  => 'long_name',
                ],
                'administrative_area_level_2' => [   
                    'name'  => 'province',
                    'label' => 'Provincia',
                    'type'  => 'short_name',
                ],
                'country' => [  
                    'name'  => 'country',
                    'label' => 'Nazione',
                    'type'  => 'short_name',
                ],
            ],
        ]);

the 'type' attribute is optional and can be set to 'short_name' or 'long_name'. The default value is 'long_name'.

Each component needs a column in the table. The autocomplete field is not stored so it doesn't need a column in the table.

A complete migration would look like this:

public function up()
    {
        Schema::create('addresses', function (Blueprint $table) {
            $table->increments('id');
            $table->string('address_line_1');
            $table->string('address_line_2');
            $table->string('city');
            $table->string('region');
            $table->string('province');
            $table->string('postal_code');
            $table->string('country');
            $table->timestamps();
        });
    }

All the fields can be validated with their own rules like every standard field.

M4rk3tt0 avatar Oct 17 '16 19:10 M4rk3tt0

Thank you @OwenMelbz :smile: I will implement the changes you suggested!

About the API key, do you mean using the env() variable directly in the api call like this

<script src="https://maps.googleapis.com/maps/api/js?key={{ $env('GOOGLE_API_KEY') }} ...></script>

instead of

<script src="https://maps.googleapis.com/maps/api/js?key={{ $field['google_api_key'] }} ...></script>

and eliminate the google_api_key attribute inside the field?

Or I can check if the google_api_key exists in the field attribute, if not I check if it exists in the .env file.

Enhancement

I have to admit that I was inspired by the address field you created using Agolia Places ( congratulations btw :grin: ) but I needed something more complex. I first tried with Agolia Places but the Open Street Map isn't as complete as Google Maps and I was really disappointed when it couldn't find office address!

I was thinking to enhance my address field giving the possibility to be used like the address field that already exists but using Google Places API. It would look like this

BASIC FIELD

$this->crud->addField([
            'name'              => 'address',
            'label'             => 'Address',
            'type'              => 'address_form_google',

            // optional
            'store_as_json' => true
        ]);

ADVANCED FIELD

$this->crud->addField([
            'name'              => 'address',
            'label'             => 'Address',
            'type'              => 'address_form_google',

            'components' =>  [
                'COMPONENT' => [   
                    'name'  => 'address_line_1',
                    'label' => 'Street',
                    'type'  => 'long_name', // Optional
                ],
                // Other components
            ],
        ]);

What do you think about?

M4rk3tt0 avatar Oct 25 '16 09:10 M4rk3tt0

Is this possible to get location from our location or device like using HTML5 instead typing specific address? Would be useful if that happens. :)

elraghifary avatar Oct 25 '16 12:10 elraghifary

@M4rk3tt0 your suggested enhancement (both basic and advanced) sound PERFECT to me. I like the "components" name for that attribute. I also like the idea of also being able to define the Google API key in an environment variable. Could we call the field "google_address"? I'm thinking that we'll also call the other one "algolia_address" and in time we'll phase out the simple "address" one.

@elraghifary I think that might be overkill. CRUDs are usually for inserting a lot of information, so A LOT of it won't be about your current location, but some other location. So geolocation might end up being more annoying that useful, in most cases.

Cheers guys!

tabacitu avatar Oct 25 '16 12:10 tabacitu

@M4rk3tt0 Im thinking of something waterfall like allowing multiple locations, for ultimate flexibility for the user so maybe like

$googleApiKey = isset( $field['google_api_key'] ) ? $field['google_api_key']  : ( config('backpack.google_api_key', env('GOOGLE_API_KEY', null) );


<script src="https://maps.googleapis.com/maps/api/js?key={{ $googleApiKey }} ...></script>

So that way

  • A user can pass in a api key if they want, otherwise
  • It can pull it from their config (this might pull from their env file, and helps users who have diff api keys for different services)
  • If its not found in the config, it will try find it in the env variables
  • else I imagine google will just 400 error.

Then they can set it globally.

What do you think to that?

But I definitely like the idea of a more complex one, maybe we could merge the 2 features? create something like 'provider' => 'google' //others algolia this way would allow more flexibility for users? and would also mean its backwards compatible if we keep the default as Algolia and just document it nicely?

@elraghifary thats a nice idea :) Yes its possible to get an estimated lat / long from the HTML geolocation function similar to navigator.geolocation.getCurrentPosition(callBack); I don't think this fits in with Backpacks current roadmap, but as a community member you're more than welcome to submit PR with this functionality, or maybe liaise with @M4rk3tt0 to see if its something he wants to expand his PR with? maybe another option! 'enable_html5_location' => true etc

OwenMelbz avatar Oct 25 '16 12:10 OwenMelbz

@tabacitu I'm glad you like it! I will work on it as soon as I can :smile:

@OwenMelbz Yes that makes sense, I will implement the api key the way you suggested. We can definitely merge the two address fields together when they are ready.

@elraghifary It is possible to get the location using HTML5 and use the Reverse Geocoding of Google Geolocation API to get the address but it would be only an estimate. The user would have to fill the fields manually because the address would be wrong. You can try if you want. Get an API KEY and send a get request the url that you find HERE replacing the latitude and longitude with the one you get from HTML5.

The geolocation could be useful to reduce Google Places API search area.

M4rk3tt0 avatar Oct 25 '16 15:10 M4rk3tt0

Recommend adding an option to change the autocomplete search (e.g. 'establishment').

ghost avatar Oct 31 '16 15:10 ghost

@tabacitu What about merging this?

EmanueleCoppola avatar Oct 24 '17 18:10 EmanueleCoppola

Possible to add country restriction option in the address_google CRUD options?

// Set initial restrict to the greater list of countries.
$autocomplete.setComponentRestrictions(
    {'country': ['us', 'pr', 'vi', 'gu', 'mp']}
);

kiddtang avatar Apr 17 '20 06:04 kiddtang

There are some good ideas that we can extract from here to apply in our google_address field, but I think it's time to put this 8 year issue behind us.

Thanks everyone that worked on this, and sorry it didn't get merged.

Cheers

pxpm avatar Sep 12 '22 13:09 pxpm