Skip to content

Commit

Permalink
Using vuetify-google-autocomplete with vue2-google-maps
Browse files Browse the repository at this point in the history
  • Loading branch information
todd committed Oct 27, 2020
1 parent c46b9cb commit 2dc464d
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 71 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,35 @@ Vue.use(VuetifyGoogleAutocomplete, {
apiKey: '...', // Can also be an object. E.g, for Google Maps Premium API, pass `{ client: <YOUR-CLIENT-ID> }`
version: '...', // Optional
language: '...', // Optional
vueGoogleMapsCompatibility: false, // Optional (default: false) - true, requires vue2-google-maps to be configured see https://github.com/xkjyeah/vue-google-maps
});
```

For use with `vue2-google-maps`
```javascript
import Vue from 'vue';
import * as VueGoogleMaps from 'vue2-google-maps';
import VuetifyGoogleAutocomplete from 'vuetify-google-autocomplete';

// @see https://www.npmjs.com/package/vue2-google-maps
Vue.use(VueGoogleMaps, {
load: {
key: 'xxxxxxxxs',
// This is required to use the Autocomplete plugin
libraries: 'places', // 'places,drawing,visualization'
},
});

Vue.use(VuetifyGoogleAutocomplete, {
/*
not used as loaded with component
apiKey: key,
*/
vueGoogleMapsCompatibility: true,
});


```
### For version <= 1.1.0

This component uses Google Maps Places API to get geo suggests for autocompletion, so you have to include the Google Maps Places API in the `<head>` of your HTML:
Expand Down
175 changes: 105 additions & 70 deletions src/vga/VuetifyGoogleAutocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -910,12 +910,16 @@ export default {
lat: position.coords.latitude,
lng: position.coords.longitude,
};
const circle = new window.google.maps.Circle({
center: geolocation,
radius: position.coords.accuracy,

// initialise up knowing that google maps is actually loaded
this.setupGmapApi(() => {
const circle = new window.google.maps.Circle({
center: geolocation,
radius: position.coords.accuracy,
});
this.autocomplete.setBounds(circle.getBounds());
this.geolocateSet = true;
});
this.autocomplete.setBounds(circle.getBounds());
this.geolocateSet = true;
});
}
}
Expand All @@ -942,77 +946,104 @@ export default {
}
}

this.autocomplete = new window.google.maps.places.Autocomplete(
document.getElementById(this.id),
options,
);
// initialise up knowing that google maps is actually loaded
this.setupGmapApi(() => {
this.autocomplete = new window.google.maps.places.Autocomplete(
document.getElementById(this.id),
options,
);

// Override the default placeholder
// text set by Google with the
// placeholder prop value or an empty value.
document.getElementById(this.id)
.setAttribute('placeholder', this.placeholder ? this.placeholder : '');
// this is potentially inside a promise so the autocomplete MUST exist to add the listener
this.autocomplete.addListener('place_changed', () => {
const place = this.autocomplete.getPlace();

this.autocomplete.addListener('place_changed', () => {
const place = this.autocomplete.getPlace();
// if (!place || !place.geometry) {
if (Object.keys(place).length < 2) {
// User entered the name of a Place that was not suggested and
// pressed the Enter key, or the Place Details request failed.
this.$emit('no-results-found', place);
return;
}

// if (!place || !place.geometry) {
if (Object.keys(place).length < 2) {
// User entered the name of a Place that was not suggested and
// pressed the Enter key, or the Place Details request failed.
this.$emit('no-results-found', place);
return;
}
const returnData = {};

const returnData = {};
if (place.name !== undefined && this.placeName) {
this.autocompleteText = place.name;
} else if (place.formatted_address !== undefined) {
this.autocompleteText = place.formatted_address;
}

if (place.name !== undefined && this.placeName) {
this.autocompleteText = place.name;
} else if (place.formatted_address !== undefined) {
this.autocompleteText = place.formatted_address;
}
if (place.address_components !== undefined) {
// Get each component of the address from the place details
for (let i = 0; i < place.address_components.length; i += 1) {
const addressType = place.address_components[i].types[0];

if (place.address_components !== undefined) {
// Get each component of the address from the place details
for (let i = 0; i < place.address_components.length; i += 1) {
const addressType = place.address_components[i].types[0];
if (this.addressComponents[addressType]) {
const val = place.address_components[i][this.addressComponents[addressType]];
returnData[addressType] = val;
}
}
if (place.geometry) {
returnData.latitude = place.geometry.location.lat();
returnData.longitude = place.geometry.location.lng();
}

if (this.addressComponents[addressType]) {
const val = place.address_components[i][this.addressComponents[addressType]];
returnData[addressType] = val;
// additional fields available in google places results
if (place.name) {
returnData.name = place.name;
}
if (place.photos) {
returnData.photos = place.photos;
}
if (place.place_id) {
returnData.place_id = place.place_id;
}
}
if (place.geometry) {
returnData.latitude = place.geometry.location.lat();
returnData.longitude = place.geometry.location.lng();
}

// additional fields available in google places results
if (place.name) {
returnData.name = place.name;
}
if (place.photos) {
returnData.photos = place.photos;
}
if (place.place_id) {
returnData.place_id = place.place_id;
// return returnData object and PlaceResult object
this.$emit('placechanged', returnData, place, this.id);

// update autocompleteText then emit change event
this.lastSelectedPlace = this.autocompleteText;
this.onChange();
if (this.validateOnBlur) {
// manually validate the underlying v-text-field because
// selecting an option causes the field to lose focus
// before the place_changed event is emitted and we have
// a chance to fill the field with the formatted address
this.$refs.textField.validate();
}
}
});
});

// return returnData object and PlaceResult object
this.$emit('placechanged', returnData, place, this.id);

// update autocompleteText then emit change event
this.lastSelectedPlace = this.autocompleteText;
this.onChange();
if (this.validateOnBlur) {
// manually validate the underlying v-text-field because
// selecting an option causes the field to lose focus
// before the place_changed event is emitted and we have
// a chance to fill the field with the formatted address
this.$refs.textField.validate();
}
// Override the default placeholder
// text set by Google with the
// placeholder prop value or an empty value.
document.getElementById(this.id)
.setAttribute('placeholder', this.placeholder ? this.placeholder : '');
},

/**
* Uses the gmap deferred loading strategy from the third-party library rather than the
* default strategy of this library.
*
* @remarks
* fixes https://github.com/MadimetjaShika/vuetify-google-autocomplete/issues/60
* @private
*/
setupGmapApi(callback) {
if (this.$vueGoogleMapsCompatibility) {
if (Object.prototype.hasOwnProperty.call(this, '$gmapApiPromiseLazy')) {
this.$gmapApiPromiseLazy()
.then(() => callback());
}
});
} else if (Object.prototype.hasOwnProperty.call(window, 'google')) {
callback();
} else {
// no logger with this library. But this is a likely configuration error condition
// Note: unwilling to throw an Error
}
},
},
/**
Expand All @@ -1029,12 +1060,7 @@ export default {
*/
mounted() {
this.vgaMapState = window.vgaMapState;
// if (Object.prototype.hasOwnProperty.call(window, 'google')
// && Object.prototype.hasOwnProperty.call(window, 'maps')) {
if (Object.prototype.hasOwnProperty.call(window, 'google')) {
// we've been here before. just need to get Autocomplete loaded
this.setupGoogle();
}
this.setupGmapApi(this.setupGoogle);
},
/**
* @mixin
Expand Down Expand Up @@ -1228,12 +1254,21 @@ export default {
this.enableGeolocation = newVal;
},

/**
* Watches the internal initialisation flag (callback from google maps loading) and
* when changes works out the google maps load strategy. In the case that requires
* vue2-google-maps compatibility the known lazy load strategy from that library is used.
*/
'vgaMapState.initMap': function vgaMapStateInitMap(value) {
if (value) {
this.setupGoogle();
this.setupGmapApi(this.setupGoogle);
}
},

'window.vueGoogleMapsInit': function vgaMapStateInitMap() {
window.vgaMapState.initMap = true;
},

/**
* Update the SDK types option whenever it changes from the parent.
*/
Expand Down
23 changes: 22 additions & 1 deletion src/vga/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,29 @@ if (typeof window !== 'undefined') {
}

VuetifyGoogleAutocomplete.install = (Vue, options) => {
// Set defaults
options = {
/*
* Allow this component to be used in conjunction with vue2-google-maps and loads maps API
* via the other component.
*
* @see https://github.com/MadimetjaShika/vuetify-google-autocomplete/issues/60
*/
vueGoogleMapsCompatibility: false,
...options,
};

// add Vue.$vueGoogleMapsCompatibility flag to be used for deferred loading via vue2-google-maps lazy loader
Vue.mixin({
created() {
this.$vueGoogleMapsCompatibility = options.vueGoogleMapsCompatibility;
},
});

if (options.apiKey) {
loadGoogleMaps(options.apiKey, options.version, options.language);
if (!options.vueGoogleMapsCompatibility) {
loadGoogleMaps(options.apiKey, options.version, options.language);
} // else use vue2-google-maps to load maps via deferred/promise-based loading mechanism on Vue.$gmapApiPromiseLazy
}

Vue.component(VuetifyGoogleAutocomplete.name, VuetifyGoogleAutocomplete);
Expand Down

0 comments on commit 2dc464d

Please sign in to comment.