Created
November 27, 2019 10:01
-
-
Save Haroenv/c73d1e3f5dd887d3e21751ec02c4b7d9 to your computer and use it in GitHub Desktop.
A Vue + Places.js widget
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<!-- container for places.js --> | |
<div> | |
<div id="algolia-places" /> | |
</div> | |
</template> | |
<script> | |
import { createWidgetMixin } from 'vue-instantsearch'; | |
import places from 'places.js'; | |
import { places_config, store } from '../store.js'; | |
let placeName; | |
const connectPlaces = ( | |
renderFn, | |
unmountFn | |
) => (/* widgetParams, if this would become reusable */) => { | |
return { | |
init() { | |
renderFn({ nearMe: undefined }, true); | |
}, | |
render({ state }) { | |
renderFn({ nearMe: state.aroundLatLngViaIP === 'true' }, false); | |
}, | |
dispose() { | |
unmountFn(); | |
}, | |
getWidgetState(uiState, { searchParameters }) { | |
return { | |
...uiState, | |
latlng: searchParameters.aroundLatLng, | |
nearme: searchParameters.aroundLatLngViaIP, | |
place: placeName, | |
}; | |
}, | |
getWidgetSearchParameters(searchParameters, { uiState }) { | |
placeName = uiState.place; | |
return searchParameters | |
.setQueryParameter('aroundLatLng', uiState.latlng) | |
.setQueryParameter('aroundLatLngViaIP', uiState.nearme); | |
}, | |
}; | |
}; | |
export default { | |
mixins: [createWidgetMixin({ connector: connectPlaces })], | |
data() { | |
return { | |
instance: null, | |
}; | |
}, | |
mounted() { | |
// make sure Vue does not know about the input | |
// this way it can properly unmount | |
this.input = document.createElement('input'); | |
this.input.placeholder = 'e.g. town, city, street'; | |
if (placeName) { | |
setTimeout(() => { | |
this.instance.setVal(placeName); | |
}, 0); | |
} | |
this.$el.appendChild(this.input); | |
this.addNearMeListener(); | |
this.instance = places({ | |
appId: places_config.APP_ID, | |
apiKey: places_config.API_KEY, | |
container: this.input, | |
}).configure({ | |
countries: ['GB', 'IE'], | |
}); | |
this.onChange = e => { | |
placeName = e.suggestion.value; | |
this.instantSearchInstance.helper | |
.setQueryParameter( | |
'aroundLatLng', | |
e.suggestion.latlng.lat + ',' + e.suggestion.latlng.lng | |
) | |
.setQueryParameter('aroundLatLngViaIP', undefined); | |
this.instantSearchInstance.helper.search(); | |
}; | |
this.onClear = () => { | |
store.setPlacesDialogOpened(false); | |
placeName = null; | |
this.instantSearchInstance.helper | |
.setQueryParameter('aroundLatLng', undefined) | |
.setQueryParameter('aroundLatLngViaIP', undefined); | |
this.instantSearchInstance.helper.search(); | |
}; | |
this.onShown = () => { | |
store.setPlacesDialogOpened(true); | |
} | |
this.onClosed = () => { | |
store.setPlacesDialogOpened(false); | |
} | |
this.instance.on('change', this.onChange); | |
this.instance.on('clear', this.onClear); | |
this.instance.autocomplete.on('autocomplete:shown', this.onShown); | |
this.instance.autocomplete.on('autocomplete:closed', this.onClosed); | |
}, | |
beforeDestroy() { | |
this.removeNearMeListener(); | |
// if you had any "this.instance.on", also call "off" here | |
this.instance.off('change', this.onChange); | |
this.instance.off('clear', this.onClear); | |
this.instance.autocomplete.off('autocomplete:shown', this.onShown); | |
this.instance.autocomplete.off('autocomplete:closed', this.onClosed); | |
this.instance.destroy(); | |
}, | |
methods: { | |
addNearMeListener() { | |
this.onInputChange = () => { | |
if (this.state.nearMe && this.input.value !== 'Near Me') { | |
placeName = null; | |
this.instance.setVal(''); | |
this.instantSearchInstance.helper | |
.setQueryParameter('aroundLatLng', undefined) | |
.setQueryParameter('aroundLatLngViaIP', undefined); | |
this.instantSearchInstance.helper.search(); | |
this.removeNearMeListener(); | |
} | |
}; | |
this.input.addEventListener('input', this.onInputChange); | |
}, | |
removeNearMeListener() { | |
if (this.onInputChange) { | |
this.input.removeEventListener('input', this.onInputChange); | |
this.onInputChange = null; | |
} | |
}, | |
}, | |
}; | |
</script> | |
<style lang="scss" scoped> | |
/deep/ .ap-dropdown-menu.ap-with-places .ap-suggestion .ap-suggestion-icon { | |
background-size: 14px 21px; | |
background-repeat: no-repeat; | |
background-image: url(~@/assets/location-pin.png); | |
display: inline-block; | |
width: 14px; | |
height: 21px; | |
svg { | |
display: none; | |
} | |
} | |
/deep/ .algolia-places .ap-icon-pin { | |
display: none; | |
} | |
/deep/ .ap-input { | |
background-size: 18px 27px; | |
background-repeat: no-repeat; | |
background-image: url(~@/assets/location-pin.png); | |
background-position: 17px 11px; | |
padding: 15px 15px 15px 51px !important; | |
} | |
// mobile header | |
@media screen and (max-width: $tablet) { | |
/deep/ .ap-dropdown-menu.ap-with-places { | |
width: calc(100% + 44px); | |
top: 60px !important; | |
left: -22px !important; | |
} | |
/deep/ .algolia-places .ap-icon-clear { | |
position: absolute !important; | |
top: 15px; | |
right: 6px !important; | |
width: 21px; | |
height: 21px; | |
border: none; | |
padding: 0; | |
cursor: pointer; | |
svg { | |
width: 100%; | |
height: 100%; | |
fill: #fff; | |
@include theme-value(background-color, brand-color-one); | |
border-radius: 100%; | |
padding: 4px | |
} | |
} | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment